-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnullfinder.cc
171 lines (153 loc) · 5.25 KB
/
nullfinder.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/** File: nullfinder.cc
Author: Candice Quates
Program: nullfinder
Takes argument of a file of dumped gpu memory, attempts to divine structure
by searching for blocks of nulls which have been added for padding.
Default block of nulls to search for is 8. Much larger blocks are
sometimes helpful
File parsing code lifted from sdhash, apache license (Roussev/Quates 2013)
General structure and command line arguments lifted from zsniff. (apache license)
*/
/* compile with:
g++ -std=c++0x -o nullf nullfinder.cc map_file.cc error.cc
*/
#include <vector>
#include <cstddef>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#define VERSION "nullfinder 0.2 by Candice Quates July 2015"
#include "util.h"
int
writeExtracted(std::vector<unsigned char> &image, std::string filename) {
std::string outfilename = filename+".extract";
std::filebuf fb;
fb.open (outfilename.c_str(),std::ios::out|std::ios::binary);
if (fb.is_open()) {
std::ostream os(&fb);
os.write((const char *)image.data(), image.size());
fb.close();
return 0;
} else {
std::cerr << "nullfind: cannot write to " << outfilename << std::endl;
return 1;
}
}
// using null size default to 8 nulls
// option for extract/noextract
// null size changing does not work yet
// other desired feature: use stringbuilder to make pretty hex address filenames
int
main(int argc, char *argv[])
{
bool extract = false;
if (argc < 2 ) {
std::cout << VERSION << std::endl << std::endl;
std::cout << "Usage: "<< argv[0] << " [--extract] [--nulls 8] filename(s) " << std::endl;
return 1;
}
bool nullsm=false;
uint32_t nullssize=8;
// look for extract and nulls size
for (int i=0; i<argc; i++) {
if (std::string("--extract").compare(std::string(argv[i]))==0) {
extract=true;
}
if (nullsm==true) {
if (isdigit(argv[i][0])) {
nullssize=atoi(argv[i]);
} else {
std::cerr << "usage: "<< argv[0] << " [--extract] [--nulls 8] filename(s) " << std::endl;
return 1;
}
nullsm=false;
}
if (std::string("--nulls").compare(std::string(argv[i]))==0) {
nullsm=true;
}
}
nullsm=false;
//loop for multiple files here -- from prior code but does work.
for (int i=1; i<argc; i++) {
if (std::string("--extract").compare(std::string(argv[i]))==0) {
continue;
}
// nulls marker to ignore argument after --block
if (nullsm==true) {
nullsm=false;
continue;
}
if (std::string("--nulls").compare(std::string(argv[i]))==0) {
nullsm=true;
continue;
}
const char* filename = argv[i] ;
//load files -- the sdhash methods reliably parse files with nulls
processed_file_t *mfile=process_file(filename);
if (mfile->size == 0) {
std::cerr << "nullf: file " << filename << " empty or not found" << std::endl;
return 1;
}
std::cout << "nullf processing: "<< filename << std::endl;
uint8_t current=0;
uint64_t range=0;
uint64_t nullcount=0;
uint64_t startaddr=0;
// I am well aware that there are prettier and more
// elegant ways to do this, but this is much faster
// than I expected it to be (ie, a few minutes on a VM for 2gb file)
for (uint64_t n=0; n < mfile->size ; n++) {
current=(uint8_t)*(mfile->buffer+n);
if (n==0 && current != 0)
std::cout<< std::hex <<n <<" data begins ";
if (current == 0) {
nullcount++;
if (range != 1 && nullcount == nullssize) {
std::cout<< std::hex <<n <<" ends, size ";
std::cout << std::dec << n-startaddr << std::endl;
std::cout<< std::hex <<n <<" nulls begin " ;
// extract data
if (extract) {
std::vector<unsigned char> image;
image.resize(n-(nullssize-1)-startaddr);
for (uint64_t x=0,y=startaddr; y<n-(nullssize-1); x++,y++) {
image[x]=(unsigned char)*(mfile->buffer+y);
}
std::stringstream builder;
builder << filename<< "-"<< std::hex << startaddr;
writeExtracted(image,builder.str());
}
range=1;
startaddr=0;
}
} else {
// if we've changed state, note that.
if (range == 1) {
std::cout<< std::hex <<n <<" end "<< std::endl;
std::cout<< std::hex <<n <<" data begins ";
startaddr=n;
}
range=0;
nullcount = 0;
}
}
// If we've reached EOF and are in a block of data,
// extract if asked.
if (nullcount==0) {
std::cout<< std::hex <<mfile->size<<" ends, " ;
std::cout << std::dec << (mfile->size)-startaddr << std::endl;
if (extract) {
std::vector<unsigned char> image;
image.resize((mfile->size)-(nullssize-1)-startaddr);
for (uint64_t x=0,y=startaddr; y<(mfile->size)-(nullssize-1); x++,y++) {
image[x]=(unsigned char)*(mfile->buffer+y);
}
std::stringstream builder;
builder << filename<< "-"<< std::hex << startaddr;
writeExtracted(image,builder.str());
}
}
} // loop for parsing multiple files
return 0;
}