Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
JLnkParser.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2011-2016 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.coreutils;
20
21import java.io.*;
22import java.nio.ByteBuffer;
23import java.nio.ByteOrder;
24import java.util.ArrayList;
25import java.util.Arrays;
26import java.util.List;
27import java.util.logging.Level;
28import org.sleuthkit.autopsy.coreutils.LnkEnums.CommonCLSIDS;
29import org.sleuthkit.autopsy.coreutils.LnkEnums.DriveType;
30import org.sleuthkit.autopsy.coreutils.LnkEnums.NetworkProviderType;
31
38public class JLnkParser {
39
40 private byte[] content;
41 private static final Logger logger = Logger.getLogger(JLnkParser.class.getName());
42
43 public JLnkParser(InputStream is, int length) {
44 content = new byte[length];
45 try {
46 is.read(content);
47 } catch (IOException ex) {
48 Logger.getLogger(JLnkParser.class.getName()).log(Level.WARNING, "Error reading input stream", ex); //NON-NLS
49 }
50 }
51
52 public JLNK parse() throws JLnkParserException {
53 try {
54 ByteBuffer bb = ByteBuffer.wrap(content);
55 bb.order(ByteOrder.LITTLE_ENDIAN);
56 int header = bb.getInt();
57 ByteBuffer linkClassIdentifier = bb.get(new byte[16]);
58 int linkFlags = bb.getInt();
59 int fileAttributes = bb.getInt();
60 long crtime = bb.getLong();
61 long atime = bb.getLong();
62 long mtime = bb.getLong();
63 int fileSize = bb.getInt();
64 int iconIndex = bb.getInt();
65 int showCommand = bb.getInt();
66 short hotkey = bb.getShort();
67 bb.get(new byte[10]); // reserved (???)
68 List<String> linkTargetIdList = new ArrayList<>();
69 if ((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag())
70 == LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) {
71 int idListSize = bb.getShort();
72 int bytesRead = 0;
73 List<byte[]> linkTargetIdListBytes = new ArrayList<>();
74 while (true) {
75 short itemIdSize = bb.getShort();
76 if (itemIdSize == 0) {
77 bytesRead += 2; // two null bytes to terminate id list
78 break;
79 }
80 byte[] theArray = new byte[itemIdSize - 2];
81 bb.get(theArray); // an idlist data object
82 linkTargetIdListBytes.add(theArray);
83 bytesRead += itemIdSize;
84 }
85 linkTargetIdList = parseLinkTargetIdList(linkTargetIdListBytes);
86 }
87 boolean hasUnicodeLocalBaseAndCommonSuffixOffset = false;
88 String localBasePath = null;
89 String commonPathSuffix = null;
90 String localBasePathUnicode = null;
91 String commonPathSuffixUnicode = null;
92 int driveSerialNumber = -1;
93 DriveType driveType = null;
94 String volumeLabel = null;
95 int commonNetworkRelativeLinkFlags = -1;
96 NetworkProviderType networkProviderType = null;
97 boolean unicodeNetAndDeviceName = false;
98 String netName = null;
99 String netNameUnicode = null;
100 String deviceName = null;
101 String deviceNameUnicode = null;
102
103 if ((linkFlags & LnkEnums.LinkFlags.HasLinkInfo.getFlag())
104 == LnkEnums.LinkFlags.HasLinkInfo.getFlag()) {
105 int startOfLinkInfo = bb.position();
106 int linkInfoSize = bb.getInt();
107 int linkInfoHeaderSize = bb.getInt();
108 hasUnicodeLocalBaseAndCommonSuffixOffset = linkInfoHeaderSize >= 0x24;
109 int linkInfoFlags = bb.getInt();
110 int volumeIdOffset = bb.getInt();
111 int localBasePathOffset = bb.getInt();
112 int commonNetworkRelativeLinkOffset = bb.getInt();
113 int commonPathSuffixOffset = bb.getInt();
114 int localBasePathOffsetUnicode = 0;
115 int commonPathSuffixOffsetUnicode = 0;
116 if (hasUnicodeLocalBaseAndCommonSuffixOffset) {
117 localBasePathOffsetUnicode = bb.getInt();
118 commonPathSuffixOffsetUnicode = bb.getInt();
119 }
120 if ((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
121 == LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag()) {
122 bb.position(startOfLinkInfo + volumeIdOffset);
123 int volumeIdSize = bb.getInt();
124 driveType = DriveType.valueOf(bb.getInt());
125 driveSerialNumber = bb.getInt();
126 int volumeLabelOffset = bb.getInt();
127 if (volumeLabelOffset != 0x14) {
128 volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffset, false, volumeIdSize - 0x10);
129 } else {
130 int volumeLabelOffsetUnicode = bb.getInt();
131 volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffsetUnicode, false, volumeIdSize - 0x14);
132 }
133 localBasePath = parseLocalBasePath(startOfLinkInfo + localBasePathOffset, false);
134 }
135 if ((linkInfoFlags & LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag())
136 == LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag()) {
137 bb.position(startOfLinkInfo + commonNetworkRelativeLinkOffset);
138 int commonNetworkRelativeLinkSize = bb.getInt();
139 commonNetworkRelativeLinkFlags = bb.getInt();
140 int netNameOffset = bb.getInt();
141 unicodeNetAndDeviceName = netNameOffset > 0x14;
142 int deviceNameOffset = bb.getInt();
143 int netType = bb.getInt();
144 int netNameOffsetUnicode = 0;
145 int deviceNameOffsetUnicode = 0;
146 if (unicodeNetAndDeviceName) {
147 netNameOffsetUnicode = bb.getInt();
148 deviceNameOffsetUnicode = bb.getInt();
149 }
150 netName = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffset, false);
151 if (unicodeNetAndDeviceName) {
152 netNameUnicode = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffsetUnicode, true);
153 }
154 if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag())
155 == LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag()) {
156 networkProviderType = LnkEnums.NetworkProviderType.valueOf(netType);
157 }
158 if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag())
159 == LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag()) {
160 deviceName = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffset, false);
161 if (unicodeNetAndDeviceName) {
162 deviceNameUnicode = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffsetUnicode, true);
163 }
164 }
165 }
166 commonPathSuffix = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffset, false);
167 if (((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
168 == LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
169 && hasUnicodeLocalBaseAndCommonSuffixOffset) {
170 localBasePathUnicode = parseLocalBasePath(startOfLinkInfo + localBasePathOffsetUnicode, true);
171 commonPathSuffixUnicode = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffsetUnicode, true);
172 }
173
174 bb.position(startOfLinkInfo + linkInfoSize);
175 }
176 String name = null;
177 if ((linkFlags & LnkEnums.LinkFlags.HasName.getFlag())
178 == LnkEnums.LinkFlags.HasName.getFlag()) {
179 name = readStringData(bb);
180 }
181 String relativePath = null;
182 if ((linkFlags & LnkEnums.LinkFlags.HasRelativePath.getFlag())
183 == LnkEnums.LinkFlags.HasRelativePath.getFlag()) {
184 relativePath = readStringData(bb);
185 }
186 String workingDir = null;
187 if ((linkFlags & LnkEnums.LinkFlags.HasWorkingDir.getFlag())
188 == LnkEnums.LinkFlags.HasWorkingDir.getFlag()) {
189 workingDir = readStringData(bb);
190 }
191 String arguments = null;
192 if ((linkFlags & LnkEnums.LinkFlags.HasArguments.getFlag())
193 == LnkEnums.LinkFlags.HasArguments.getFlag()) {
194 arguments = readStringData(bb);
195 }
196 String iconLocation = null;
197 if ((linkFlags & LnkEnums.LinkFlags.HasIconLocation.getFlag())
198 == LnkEnums.LinkFlags.HasIconLocation.getFlag()) {
199 iconLocation = readStringData(bb);
200 }
201
202 return new JLNK(header, linkClassIdentifier.array(), linkFlags, fileAttributes,
203 crtime, atime, mtime, fileSize, iconIndex, showCommand, hotkey,
204 linkTargetIdList,
205 hasUnicodeLocalBaseAndCommonSuffixOffset, localBasePath,
206 commonPathSuffix, localBasePathUnicode, commonPathSuffixUnicode,
207 name, relativePath, workingDir, arguments, iconLocation, driveSerialNumber,
208 driveType, volumeLabel, commonNetworkRelativeLinkFlags,
209 networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
210 deviceName, deviceNameUnicode);
211 } catch (Exception e) {
212 throw new JLnkParserException(e);
213 }
214 }
215
216 private String readStringData(ByteBuffer bb) {
217 short countCharacters = bb.getShort();
218 if (countCharacters == 0) {
219 return null;
220 }
221 byte[] theString = new byte[countCharacters * 2];
222 bb.get(theString);
223 try {
224 return new String(theString, "UTF-16LE");
225 } catch (UnsupportedEncodingException ex) {
226 logger.info("Shouldn't happen"); //NON-NLS
227 return null;
228 }
229 }
230
231 private String parseString(int offset, boolean unicode, int maxlen) {
232 ByteBuffer bb = ByteBuffer.wrap(content);
233 bb.order(ByteOrder.LITTLE_ENDIAN);
234 bb.position(offset);
235 StringBuilder sb = new StringBuilder(bb.limit());
236 int i = 0;
237 while (bb.remaining() > 0 && (i < maxlen || maxlen == -1)) // safer
238 {
239 char c;
240 if (unicode) {
241 c = bb.getChar();
242 } else {
243 c = (char) bb.get();
244 }
245 if (c == '\0') {
246 break;
247 }
248 sb.append(c);
249 i++;
250 }
251 return sb.toString();
252 }
253
254 private String parseCommonPathSuffix(int offset, boolean unicode) {
255 return parseString(offset, unicode, -1);
256
257 }
258
259 private String parseLocalBasePath(int offset, boolean unicode) {
260 return parseString(offset, unicode, -1);
261
262 }
263
264 private String parseNetName(int offset, boolean unicode) {
265 return parseString(offset, unicode, -1);
266 }
267
268 private String parseDeviceName(int offset, boolean unicode) {
269 return parseString(offset, unicode, -1);
270 }
271
272 private List<String> parseLinkTargetIdList(List<byte[]> idList) {
273 List<String> ret = new ArrayList<>();
274 if (!idList.isEmpty()) {
275 CommonCLSIDS clsid = CommonCLSIDS.valueOf(Arrays.copyOfRange(idList.remove(0), 2, 18));
276 switch (clsid) {
277 case CDrivesFolder:
278 ret.add(new String(Arrays.copyOfRange(idList.remove(0), 1, 17)).split("\0")[0]);
279 ret.addAll(parsePathElements(idList));
280 break;
281 case CMyDocsFolder:
282 ret.addAll(parsePathElements(idList));
283 break;
284 case IEFrameDLL:
285 break;
286 case Unknown:
287 break;
288 default:
289 break;
290 }
291 }
292 return ret;
293 }
294
295 private List<String> parsePathElements(List<byte[]> idList) {
296 List<String> ret = new ArrayList<>();
297 for (byte[] pathElement : idList) {
298 ByteBuffer bb = ByteBuffer.wrap(pathElement);
299 bb.order(ByteOrder.LITTLE_ENDIAN);
300 int offset = bb.getShort(bb.limit() - 2) - 2;
301 if (pathElement[offset + 0x02] < 0x03
302 || pathElement[offset + 0x10] >= pathElement[offset]
303 || pathElement[offset + 0x10] < 0x14) {
304 ret.add(get0xC(bb));
305 continue;
306 }
307 if (pathElement[offset + 0x10] != 0) {
308 ret.add(getStringAt(bb, offset + pathElement[offset + 0x10], true));
309 continue;
310 } else {
311 if (pathElement[offset + 0x12] >= pathElement[offset]
312 || pathElement[offset + 0x12] < 0x14) {
313 ret.add(get0xC(bb));
314 continue;
315 } else {
316 ret.add(getStringAt(bb, offset + pathElement[offset + 0x12], false));
317 continue;
318 }
319 }
320 }
321 return ret;
322 }
323
324 private String get0xC(ByteBuffer bb) {
325 return getStringAt(bb, 0xC, false);
326 }
327
328 private String getStringAt(ByteBuffer bb, int offset, boolean unicode) {
329 byte[] nameArr = Arrays.copyOfRange(bb.array(), offset, bb.limit());
330 if (unicode) {
331 try {
332 return new String(nameArr, "UTF-16LE").split("\0")[0];
333 } catch (UnsupportedEncodingException ex) {
334 Logger.getLogger(JLnkParser.class.getName()).log(Level.SEVERE, null, ex);
335 }
336 }
337 return new String(nameArr).split("\0")[0];
338 }
339}
String parseString(int offset, boolean unicode, int maxlen)
String parseCommonPathSuffix(int offset, boolean unicode)
String parseNetName(int offset, boolean unicode)
JLnkParser(InputStream is, int length)
List< String > parseLinkTargetIdList(List< byte[]> idList)
String parseLocalBasePath(int offset, boolean unicode)
String getStringAt(ByteBuffer bb, int offset, boolean unicode)
String parseDeviceName(int offset, boolean unicode)
List< String > parsePathElements(List< byte[]> idList)
synchronized static Logger getLogger(String name)
Definition Logger.java:124

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.