1 /* Copyright (C) 2009 Trend Micro Inc.
2 * All right reserved.
3 *
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
7 * Foundation
8 */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <dirent.h>
14 #include <windows.h>
15
16 /* ads_dump
17 * Dumps every NTFS ADS found in a directory (recursive)
18 */
19
20 /* Prototypes */
21 int os_get_streams(char *full_path);
22 int read_sys_dir(char *dir_name);
23 int read_sys_file(char *file_name);
24
25 /* Global variables */
26 int ads_found = 0;
27
28
29 /* Print out streams of a file */
os_get_streams(char * full_path)30 int os_get_streams(char *full_path)
31 {
32 HANDLE file_h;
33 WIN32_STREAM_ID sid;
34 void *context = NULL;
35 char stream_name[MAX_PATH + 1];
36 char final_name[MAX_PATH + 1];
37 DWORD dwRead, shs, dw1, dw2;
38
39 /* Open file */
40 file_h = CreateFile(full_path,
41 GENERIC_READ,
42 FILE_SHARE_READ,
43 NULL,
44 OPEN_EXISTING,
45 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS,
46 NULL);
47
48 if (file_h == INVALID_HANDLE_VALUE) {
49 return 0;
50 }
51
52 /* Zero memory */
53 ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
54
55 /* Get stream header size -- should be 20 bytes */
56 shs = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid + sid.dwStreamNameSize;
57
58 while (1) {
59 if (BackupRead(file_h, (LPBYTE) &sid, shs, &dwRead,
60 FALSE, FALSE, &context) == 0) {
61 break;
62 }
63 if (dwRead == 0) {
64 break;
65 }
66
67 stream_name[0] = '\0';
68 stream_name[MAX_PATH] = '\0';
69 if (BackupRead(file_h, (LPBYTE)stream_name,
70 sid.dwStreamNameSize,
71 &dwRead, FALSE, FALSE, &context)) {
72 if (dwRead != 0) {
73 char *tmp_pt;
74 snprintf(final_name, MAX_PATH, "%s%S", full_path,
75 (WCHAR *)stream_name);
76 tmp_pt = strrchr(final_name, ':');
77 if (tmp_pt) {
78 *tmp_pt = '\0';
79 }
80 printf("Found NTFS ADS: '%s' \n", final_name);
81 ads_found = 1;
82 }
83 }
84
85 /* Get next */
86 if (!BackupSeek(file_h, sid.Size.LowPart, sid.Size.HighPart,
87 &dw1, &dw2, &context)) {
88 break;
89 }
90 }
91
92 CloseHandle(file_h);
93 return (0);
94 }
95
read_sys_file(char * file_name)96 int read_sys_file(char *file_name)
97 {
98 struct stat statbuf;
99
100 /* Get streams */
101 os_get_streams(file_name);
102 if (stat(file_name, &statbuf) < 0) {
103 return (0);
104 }
105
106 /* If directory, read the directory */
107 else if (S_ISDIR(statbuf.st_mode)) {
108 return (read_sys_dir(file_name));
109 }
110
111 return (0);
112 }
113
read_sys_dir(char * dir_name)114 int read_sys_dir(char *dir_name)
115 {
116 DIR *dp;
117 struct dirent *entry;
118 struct stat statbuf;
119
120 /* Get the number of nodes. The total number on opendir
121 * must be the same.
122 */
123 if (stat(dir_name, &statbuf) < 0) {
124 return (-1);
125 }
126
127 /* Must be a directory */
128 if (!S_ISDIR(statbuf.st_mode)) {
129 return (-1);
130 }
131
132 /* Open the directory given */
133 dp = opendir(dir_name);
134 if (!dp) {
135 return (-1);
136 }
137
138 /* Read every entry in the directory */
139 while ((entry = readdir(dp)) != NULL) {
140 char f_name[MAX_PATH + 2];
141
142 /* Ignore . and .. */
143 if ((strcmp(entry->d_name, ".") == 0) ||
144 (strcmp(entry->d_name, "..") == 0)) {
145 continue;
146 }
147
148 /* Create new file + path string */
149 snprintf(f_name, MAX_PATH + 1, "%s\\%s", dir_name, entry->d_name);
150
151 read_sys_file(f_name);
152 }
153
154 closedir(dp);
155
156 return (0);
157 }
158
main(int argc,char ** argv)159 int main(int argc, char **argv)
160 {
161 printf("%s: NTFS ADS dumper (GPL v2)\n", argv[0]);
162 printf("by Daniel B. Cid - dcid at ossec.net\n\n");
163
164 /* Print every NTFS ADS found */
165 if (argc < 2) {
166 printf("%s dir\n", argv[0]);
167 exit(1);
168 }
169
170 /* Get streams */
171 read_sys_file(argv[1]);
172
173 if (ads_found == 0) {
174 printf("No NTFS ADS found.\n");
175 }
176 return (0);
177 }
178
179