diff options
author | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-07-11 15:50:46 +0000 |
---|---|---|
committer | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-07-11 15:50:46 +0000 |
commit | 14c7f45cdae826f88dc539c8c38dd95caf305731 (patch) | |
tree | 832da054b7cfb2dc6fd63339af736625f31d21aa /utils/zenutils/source | |
parent | 7c84ede3781c27db73403bd6302f320c76a58c8c (diff) | |
download | rockbox-14c7f45cdae826f88dc539c8c38dd95caf305731.tar.gz rockbox-14c7f45cdae826f88dc539c8c38dd95caf305731.zip |
Add zook's ZenUtils to SVN
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18010 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/zenutils/source')
27 files changed, 3753 insertions, 0 deletions
diff --git a/utils/zenutils/source/CMakeLists.txt b/utils/zenutils/source/CMakeLists.txt new file mode 100755 index 0000000000..e3d44fd036 --- /dev/null +++ b/utils/zenutils/source/CMakeLists.txt | |||
@@ -0,0 +1,6 @@ | |||
1 | ADD_SUBDIRECTORY(firmware_extract) | ||
2 | ADD_SUBDIRECTORY(firmware_make) | ||
3 | ADD_SUBDIRECTORY(shared) | ||
4 | ADD_SUBDIRECTORY(update_extract) | ||
5 | ADD_SUBDIRECTORY(update_patch) | ||
6 | ADD_SUBDIRECTORY(zen_crypt) | ||
diff --git a/utils/zenutils/source/firmware_extract/CMakeLists.txt b/utils/zenutils/source/firmware_extract/CMakeLists.txt new file mode 100755 index 0000000000..3814f03612 --- /dev/null +++ b/utils/zenutils/source/firmware_extract/CMakeLists.txt | |||
@@ -0,0 +1,3 @@ | |||
1 | ADD_EXECUTABLE(firmware_extract main.cpp) | ||
2 | |||
3 | TARGET_LINK_LIBRARIES(firmware_extract shared) | ||
diff --git a/utils/zenutils/source/firmware_extract/main.cpp b/utils/zenutils/source/firmware_extract/main.cpp new file mode 100755 index 0000000000..c677a91a75 --- /dev/null +++ b/utils/zenutils/source/firmware_extract/main.cpp | |||
@@ -0,0 +1,243 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <iostream> | ||
20 | #include <ctime> | ||
21 | #include <getpot/getpot.hpp> | ||
22 | #include <utils.h> | ||
23 | #include <firmware.h> | ||
24 | |||
25 | |||
26 | static const char VERSION[] = "0.1"; | ||
27 | |||
28 | |||
29 | void print_version() | ||
30 | { | ||
31 | std::cout | ||
32 | << "firmware_extract - Extracts files from a Creative firmware." | ||
33 | << std::endl | ||
34 | << "Version " << VERSION << std::endl | ||
35 | << "Copyright (c) 2007 Rasmus Ry" << std::endl; | ||
36 | } | ||
37 | |||
38 | void print_help() | ||
39 | { | ||
40 | print_version(); | ||
41 | std::cout | ||
42 | << "Usage: firmware_extract [command] [options]" << std::endl | ||
43 | << std::endl | ||
44 | << " Commands:" << std::endl | ||
45 | << " -h,--help" << std::endl | ||
46 | << " prints this message." << std::endl | ||
47 | << " -f,--firmware [file]" << std::endl | ||
48 | << " specifies the firmware arhive file name." << std::endl | ||
49 | << std::endl | ||
50 | << " Options:" << std::endl | ||
51 | << " -V,--verbose" << std::endl | ||
52 | << " prints verbose messages." << std::endl | ||
53 | << " -p,--prefix [prefix]" << std::endl | ||
54 | << " specifies a file name prefix for the extracted files." << std::endl | ||
55 | << std::endl | ||
56 | ; | ||
57 | } | ||
58 | |||
59 | |||
60 | struct save_entry_functor | ||
61 | { | ||
62 | save_entry_functor(const std::string& fileprefix) | ||
63 | : _fileprefix(fileprefix) {} | ||
64 | |||
65 | bool operator()(const zen::firmware_entry& entry) | ||
66 | { | ||
67 | std::string filename = _fileprefix + entry.get_content_name(); | ||
68 | std::ofstream ofs; | ||
69 | ofs.open(filename.c_str(), std::ios::binary); | ||
70 | if (!ofs) | ||
71 | false; | ||
72 | |||
73 | size_t off = entry.get_content_offset(); | ||
74 | std::streamsize size = entry.get_bytes().size() - off; | ||
75 | ofs.write((const char*)&entry.get_bytes()[off], size); | ||
76 | |||
77 | return ofs.good(); | ||
78 | } | ||
79 | |||
80 | const std::string& _fileprefix; | ||
81 | }; //struct save_entry_functor | ||
82 | |||
83 | struct print_entry_functor | ||
84 | { | ||
85 | print_entry_functor(std::ostream& os, const std::string& fileprefix) | ||
86 | : _os(os), _fileprefix(fileprefix), num(0) {} | ||
87 | |||
88 | bool operator()(const zen::firmware_entry& entry) | ||
89 | { | ||
90 | std::string filename = _fileprefix + entry.get_content_name(); | ||
91 | if (!num) | ||
92 | _os << "[./" << num++ << "]" << std::endl; | ||
93 | else | ||
94 | _os << "[../" << num++ << "]" << std::endl; | ||
95 | _os << "tag = " << entry.get_name() << std::endl; | ||
96 | |||
97 | if (entry.get_content_offset()) | ||
98 | _os << "name = " << entry.get_content_name() << std::endl; | ||
99 | |||
100 | _os << "file = \'" << shared::double_quote(filename) << "\'" | ||
101 | << std::endl; | ||
102 | |||
103 | return _os.good(); | ||
104 | } | ||
105 | |||
106 | std::ostream& _os; | ||
107 | const std::string& _fileprefix; | ||
108 | int num; | ||
109 | }; //struct print_entry_functor | ||
110 | |||
111 | |||
112 | int process_arguments(int argc, char* argv[]) | ||
113 | { | ||
114 | //-------------------------------------------------------------------- | ||
115 | // Parse input variables. | ||
116 | //-------------------------------------------------------------------- | ||
117 | |||
118 | GetPot cl(argc, argv); | ||
119 | if (cl.size() == 1 || cl.search(2, "-h", "--help")) | ||
120 | { | ||
121 | print_help(); | ||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | std::string firmwarename; | ||
126 | if (cl.search("-f") || cl.search("--firmware")) | ||
127 | firmwarename = cl.next(""); | ||
128 | if (firmwarename.empty()) | ||
129 | { | ||
130 | std::cerr << "Firmware archive must be specified." << std::endl; | ||
131 | return 2; | ||
132 | } | ||
133 | |||
134 | bool verbose = false; | ||
135 | if (cl.search("-V") || cl.search("--verbose")) | ||
136 | verbose = true; | ||
137 | |||
138 | std::string prefixname = shared::remove_extension(firmwarename) + "_"; | ||
139 | if (cl.search("-p") || cl.search("--prefix")) | ||
140 | prefixname = cl.next(prefixname.c_str()); | ||
141 | |||
142 | |||
143 | //-------------------------------------------------------------------- | ||
144 | // Read the firmware archive. | ||
145 | //-------------------------------------------------------------------- | ||
146 | |||
147 | if (verbose) | ||
148 | std::cout << "[*] Reading firmware archive..." << std::endl; | ||
149 | |||
150 | zen::firmware_archive archive(false); | ||
151 | std::ifstream ifs; | ||
152 | ifs.open(firmwarename.c_str(), std::ios::binary); | ||
153 | if (!ifs) | ||
154 | { | ||
155 | std::cerr << "Failed to open the firmware archive." << std::endl; | ||
156 | return 3; | ||
157 | } | ||
158 | |||
159 | if (!archive.read(ifs)) | ||
160 | { | ||
161 | std::cerr << "Failed to read the firmware archive." << std::endl; | ||
162 | return 4; | ||
163 | } | ||
164 | |||
165 | |||
166 | //-------------------------------------------------------------------- | ||
167 | // Generate a make file for the extracted firmware archive. | ||
168 | //-------------------------------------------------------------------- | ||
169 | |||
170 | // Get make filename for the given input file. | ||
171 | std::string makefile = shared::replace_extension(firmwarename, ".mk"); | ||
172 | |||
173 | if (verbose) | ||
174 | std::cout << "[*] Producing make file..." << std::endl; | ||
175 | |||
176 | |||
177 | // Produce make file for the given input file. | ||
178 | std::ofstream ofs; | ||
179 | ofs.open(makefile.c_str(), std::ios::binary); | ||
180 | if (!ofs) | ||
181 | { | ||
182 | std::cerr << "Failed to create firmware archive make file." | ||
183 | << std::endl; | ||
184 | return 5; | ||
185 | } | ||
186 | |||
187 | time_t timeval = time(NULL); | ||
188 | ofs << "# Make file generated at: " << ctime(&timeval); | ||
189 | ofs << "endian = " << (archive.is_big_endian() ? "big" : "little") | ||
190 | << std::endl; | ||
191 | ofs << "signed = " << (archive.is_signed() ? "true" : "false") | ||
192 | << std::endl; | ||
193 | |||
194 | ofs << "[children]" << std::endl; | ||
195 | ofs << "count = " << archive.get_children().size() << std::endl; | ||
196 | |||
197 | std::for_each(archive.get_children().begin(), | ||
198 | archive.get_children().end(), | ||
199 | print_entry_functor(ofs, prefixname)); | ||
200 | |||
201 | ofs << "[neighbours]" << std::endl; | ||
202 | ofs << "count = " << archive.get_neighbours().size() << std::endl; | ||
203 | std::for_each(archive.get_neighbours().begin(), | ||
204 | archive.get_neighbours().end(), | ||
205 | print_entry_functor(ofs, prefixname)); | ||
206 | |||
207 | |||
208 | //-------------------------------------------------------------------- | ||
209 | // Save firmware entries. | ||
210 | //-------------------------------------------------------------------- | ||
211 | |||
212 | if (verbose) | ||
213 | std::cout << "[*] Saving firmware entries..." << std::endl; | ||
214 | |||
215 | std::for_each(archive.get_children().begin(), | ||
216 | archive.get_children().end(), | ||
217 | save_entry_functor(prefixname)); | ||
218 | |||
219 | std::for_each(archive.get_neighbours().begin(), | ||
220 | archive.get_neighbours().end(), | ||
221 | save_entry_functor(prefixname)); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | int main(int argc, char* argv[]) | ||
227 | { | ||
228 | try | ||
229 | { | ||
230 | return process_arguments(argc, argv); | ||
231 | } | ||
232 | catch (const std::exception& xcpt) | ||
233 | { | ||
234 | std::cerr << "Exception caught: " << xcpt.what() << std::endl; | ||
235 | return -1; | ||
236 | } | ||
237 | catch (...) | ||
238 | { | ||
239 | std::cerr << "Unknown exception caught." << std::endl; | ||
240 | return -2; | ||
241 | } | ||
242 | return -3; | ||
243 | } | ||
diff --git a/utils/zenutils/source/firmware_make/CMakeLists.txt b/utils/zenutils/source/firmware_make/CMakeLists.txt new file mode 100755 index 0000000000..518a008730 --- /dev/null +++ b/utils/zenutils/source/firmware_make/CMakeLists.txt | |||
@@ -0,0 +1,3 @@ | |||
1 | ADD_EXECUTABLE(firmware_make main.cpp) | ||
2 | |||
3 | TARGET_LINK_LIBRARIES (firmware_make shared) | ||
diff --git a/utils/zenutils/source/firmware_make/main.cpp b/utils/zenutils/source/firmware_make/main.cpp new file mode 100755 index 0000000000..b0602b6ffe --- /dev/null +++ b/utils/zenutils/source/firmware_make/main.cpp | |||
@@ -0,0 +1,261 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <iostream> | ||
20 | #include <sstream> | ||
21 | #include <getpot/getpot.hpp> | ||
22 | #include <file.h> | ||
23 | #include <firmware.h> | ||
24 | #include <utils.h> | ||
25 | |||
26 | |||
27 | static const char VERSION[] = "0.1"; | ||
28 | |||
29 | void print_version() | ||
30 | { | ||
31 | std::cout | ||
32 | << "firmware_make - Creates a Creative firmware archive." << std::endl | ||
33 | << "Version " << VERSION << std::endl | ||
34 | << "Copyright (c) 2007 Rasmus Ry" << std::endl; | ||
35 | } | ||
36 | |||
37 | void print_help() | ||
38 | { | ||
39 | print_version(); | ||
40 | std::cout << std::endl | ||
41 | << "Usage: firmware_make [command] [options]" << std::endl | ||
42 | << std::endl | ||
43 | << " Commands:" << std::endl | ||
44 | << " -h,--help" << std::endl | ||
45 | << " prints this message." << std::endl | ||
46 | << " -m,--makefile [file]" << std::endl | ||
47 | << " specifies the .mk file to build the firmware archive from." | ||
48 | << std::endl << std::endl | ||
49 | << " Options:" << std::endl | ||
50 | << " -V,--verbose" << std::endl | ||
51 | << " prints verbose messages." << std::endl | ||
52 | << " -f,--firmware [file]" << std::endl | ||
53 | << " specifies the output firmware file name" << std::endl | ||
54 | << std::endl | ||
55 | ; | ||
56 | } | ||
57 | |||
58 | dword get_tag_value(std::string tag) | ||
59 | { | ||
60 | if (tag[0] == '0' && tag[1] == 'x') | ||
61 | { | ||
62 | dword val = 0; | ||
63 | if (sscanf(tag.c_str(), "0x%08X", &val) == 1) | ||
64 | return val; | ||
65 | if (sscanf(tag.c_str(), "0x%08x", &val) == 1) | ||
66 | return val; | ||
67 | } | ||
68 | else | ||
69 | { | ||
70 | return shared::swap(*(dword*)&tag[0]); | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | bool process_child(const GetPot& mkfile, const std::string& root, int index, | ||
76 | zen::firmware_entry& entry) | ||
77 | { | ||
78 | std::stringstream sstm; | ||
79 | sstm << root << "/" << index; | ||
80 | std::string var = sstm.str() + "/tag"; | ||
81 | std::string tag = mkfile(var.c_str(), ""); | ||
82 | var = sstm.str() + "/name"; | ||
83 | std::string name = mkfile(var.c_str(), ""); | ||
84 | var = sstm.str() + "/file"; | ||
85 | std::string file = mkfile(var.c_str(), ""); | ||
86 | |||
87 | if (file.empty() || tag.empty()) | ||
88 | { | ||
89 | std::cerr << "Invalid file or tag for var: " << sstm.str() | ||
90 | << std::endl; | ||
91 | return false; | ||
92 | } | ||
93 | |||
94 | shared::bytes buffer; | ||
95 | if (!shared::read_file(file, buffer)) | ||
96 | { | ||
97 | std::cerr << "Failed to read the file: " << file << std::endl; | ||
98 | return false; | ||
99 | } | ||
100 | |||
101 | entry.get_bytes().clear(); | ||
102 | entry.get_header().tag = get_tag_value(tag); | ||
103 | size_t contoff = entry.get_content_offset(); | ||
104 | if (contoff) | ||
105 | { | ||
106 | entry.get_bytes().resize(contoff, 0); | ||
107 | if (!name.empty()) | ||
108 | { | ||
109 | size_t endoff = entry.is_big_endian() ? 1 : 0; | ||
110 | for (int i = 0; i < name.size(); ++i) | ||
111 | entry.get_bytes()[i * 2 + endoff] = name[i]; | ||
112 | } | ||
113 | } | ||
114 | entry.get_bytes().insert(entry.get_bytes().end(), buffer.begin(), | ||
115 | buffer.end()); | ||
116 | |||
117 | entry.get_header().size = entry.get_bytes().size(); | ||
118 | |||
119 | return true; | ||
120 | } | ||
121 | |||
122 | int process_arguments(int argc, char* argv[]) | ||
123 | { | ||
124 | //-------------------------------------------------------------------- | ||
125 | // Parse input variables. | ||
126 | //-------------------------------------------------------------------- | ||
127 | |||
128 | GetPot cl(argc, argv); | ||
129 | if (cl.size() == 1 || cl.search(2, "-h", "--help")) | ||
130 | { | ||
131 | print_help(); | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | std::string makefile; | ||
136 | if (cl.search("-m") || cl.search("--makefile")) | ||
137 | makefile = cl.next(""); | ||
138 | if (makefile.empty()) | ||
139 | { | ||
140 | std::cerr << "Makefile must be specified." << std::endl; | ||
141 | return 2; | ||
142 | } | ||
143 | |||
144 | std::string firmware; | ||
145 | if (cl.search("-f") || cl.search("--firmware")) | ||
146 | firmware = cl.next(""); | ||
147 | if (firmware.empty()) | ||
148 | { | ||
149 | std::cerr << "Firmware must be specified." << std::endl; | ||
150 | return 3; | ||
151 | } | ||
152 | |||
153 | bool verbose = false; | ||
154 | if (cl.search("-V") || cl.search("--verbose")) | ||
155 | verbose = true; | ||
156 | |||
157 | GetPot mkfile(makefile.c_str()); | ||
158 | if (verbose) | ||
159 | mkfile.print(); | ||
160 | |||
161 | bool big_endian; | ||
162 | std::string endian = mkfile("endian", "little"); | ||
163 | if (endian == "little") | ||
164 | { | ||
165 | big_endian = false; | ||
166 | } | ||
167 | else if (endian == "big") | ||
168 | { | ||
169 | big_endian = true; | ||
170 | } | ||
171 | else | ||
172 | { | ||
173 | std::cerr << "Invalid value of 'endian'" << std::endl; | ||
174 | return 4; | ||
175 | } | ||
176 | |||
177 | zen::firmware_archive archive(big_endian); | ||
178 | int childcount = mkfile("children/count", 0); | ||
179 | if (!childcount) | ||
180 | { | ||
181 | std::cerr << "A firmware archive must have at least one child entry." | ||
182 | << std::endl; | ||
183 | return 5; | ||
184 | } | ||
185 | |||
186 | for (int i = 0; i < childcount; i++) | ||
187 | { | ||
188 | zen::firmware_entry entry(big_endian); | ||
189 | if (!process_child(mkfile, "children", i, entry)) | ||
190 | { | ||
191 | return 6; | ||
192 | } | ||
193 | archive.get_children().push_back(entry); | ||
194 | } | ||
195 | |||
196 | int neighbourcount = mkfile("neighbours/count", 0); | ||
197 | for (int i = 0; i < neighbourcount; i++) | ||
198 | { | ||
199 | zen::firmware_entry entry(big_endian); | ||
200 | if (!process_child(mkfile, "neighbours", i, entry)) | ||
201 | { | ||
202 | return 7; | ||
203 | } | ||
204 | archive.get_neighbours().push_back(entry); | ||
205 | } | ||
206 | |||
207 | std::ofstream ofs; | ||
208 | ofs.open(firmware.c_str(), std::ios::out|std::ios::binary|std::ios::trunc); | ||
209 | if (!ofs) | ||
210 | { | ||
211 | std::cerr << "Failed to create the firmware file." << std::endl; | ||
212 | return 8; | ||
213 | } | ||
214 | |||
215 | if (!archive.write(ofs)) | ||
216 | { | ||
217 | std::cerr << "Failed to save the firmware archive." << std::endl; | ||
218 | return 9; | ||
219 | } | ||
220 | ofs.close(); | ||
221 | |||
222 | size_t length = archive.calc_size(); | ||
223 | if (!length) | ||
224 | { | ||
225 | std::cerr << "Failed to determine the size of the firmware archive." | ||
226 | << std::endl; | ||
227 | return 10; | ||
228 | } | ||
229 | |||
230 | int align = length % 4; | ||
231 | if (align) | ||
232 | { | ||
233 | shared::bytes padding(4 - align, 0); | ||
234 | if (!shared::write_file(firmware, padding, false, length)) | ||
235 | { | ||
236 | std::cerr << "Failed to write padding data." << std::endl; | ||
237 | return 11; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | int main(int argc, char* argv[]) | ||
245 | { | ||
246 | try | ||
247 | { | ||
248 | return process_arguments(argc, argv); | ||
249 | } | ||
250 | catch (const std::exception& xcpt) | ||
251 | { | ||
252 | std::cerr << "Exception caught: " << xcpt.what() << std::endl; | ||
253 | return -1; | ||
254 | } | ||
255 | catch (...) | ||
256 | { | ||
257 | std::cerr << "Unknown exception caught." << std::endl; | ||
258 | return -2; | ||
259 | } | ||
260 | return -3; | ||
261 | } | ||
diff --git a/utils/zenutils/source/shared/CMakeLists.txt b/utils/zenutils/source/shared/CMakeLists.txt new file mode 100755 index 0000000000..2e42dbbe74 --- /dev/null +++ b/utils/zenutils/source/shared/CMakeLists.txt | |||
@@ -0,0 +1,16 @@ | |||
1 | PROJECT(shared) | ||
2 | |||
3 | # source files for shared | ||
4 | SET(shared_srcs | ||
5 | cenc.cpp | ||
6 | crypt.cpp | ||
7 | file.cpp | ||
8 | firmware.cpp | ||
9 | pe.cpp | ||
10 | updater.cpp | ||
11 | utils.cpp | ||
12 | ) | ||
13 | |||
14 | ADD_LIBRARY(shared ${shared_srcs}) | ||
15 | TARGET_LINK_LIBRARIES(shared pelib) | ||
16 | TARGET_LINK_LIBRARIES(shared zlib) | ||
diff --git a/utils/zenutils/source/shared/cenc.cpp b/utils/zenutils/source/shared/cenc.cpp new file mode 100755 index 0000000000..932bee4625 --- /dev/null +++ b/utils/zenutils/source/shared/cenc.cpp | |||
@@ -0,0 +1,333 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include "cenc.h" | ||
20 | #include <firmware.h> | ||
21 | #include <stdexcept> | ||
22 | |||
23 | |||
24 | namespace { | ||
25 | const byte CODE_MASK = 0xC0; | ||
26 | const byte ARGS_MASK = 0x3F; | ||
27 | |||
28 | const byte REPEAT_CODE = 0x00; | ||
29 | const byte BLOCK_CODE = 0x40; | ||
30 | const byte LONG_RUN_CODE = 0x80; | ||
31 | const byte SHORT_RUN_CODE = 0xC0; | ||
32 | |||
33 | const byte BLOCK_ARGS = 0x1F; | ||
34 | const byte BLOCK_MODE = 0x20; | ||
35 | |||
36 | |||
37 | void decode_run(byte* dst, word len, byte val, | ||
38 | int& dstidx) | ||
39 | { | ||
40 | memset(dst + dstidx, val, len); | ||
41 | dstidx += len; | ||
42 | } | ||
43 | |||
44 | void decode_pattern(byte* src, byte* dst, | ||
45 | word len, int& srcidx, int& dstidx, | ||
46 | bool bdecode, int npasses) | ||
47 | { | ||
48 | for (int i = 0; i < npasses; i++) | ||
49 | { | ||
50 | if (bdecode) | ||
51 | { | ||
52 | for (int j = 0; j < len; j++) | ||
53 | { | ||
54 | word c, d; | ||
55 | c = src[srcidx + j]; | ||
56 | d = (c >> 5) & 7; | ||
57 | c = (c << 3) & 0xF8; | ||
58 | src[srcidx + j] = static_cast<byte>(c | d); | ||
59 | } | ||
60 | bdecode = false; | ||
61 | } | ||
62 | memcpy(dst + dstidx, src + srcidx, len); | ||
63 | dstidx += len; | ||
64 | } | ||
65 | srcidx += len; | ||
66 | } | ||
67 | }; //namespace | ||
68 | |||
69 | int zen::cenc_decode(byte* src, int srclen, byte* dst, int dstlen) | ||
70 | { | ||
71 | if (!src || !srclen || !dst || !dstlen) | ||
72 | { | ||
73 | throw std::invalid_argument("Invalid argument(s)."); | ||
74 | } | ||
75 | |||
76 | int i = 0, j = 0; | ||
77 | do | ||
78 | { | ||
79 | word c, d, e; | ||
80 | c = src[i++]; | ||
81 | switch (c & CODE_MASK) | ||
82 | { | ||
83 | case REPEAT_CODE: // 2 bytes | ||
84 | d = src[i++]; | ||
85 | d = d + 2; | ||
86 | |||
87 | e = (c & ARGS_MASK) + 2; | ||
88 | |||
89 | decode_pattern(src, dst, e, i, j, false, d); | ||
90 | break; | ||
91 | |||
92 | case BLOCK_CODE: // 1/2/3 bytes | ||
93 | d = c & BLOCK_ARGS; | ||
94 | if (!(c & BLOCK_MODE)) | ||
95 | { | ||
96 | e = src[i++]; | ||
97 | e = (d << 8) + (e + 0x21); | ||
98 | |||
99 | d = static_cast<word>(i ^ j); | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | e = d + 1; | ||
104 | |||
105 | d = static_cast<word>(i ^ j); | ||
106 | } | ||
107 | if (d & 1) | ||
108 | { | ||
109 | i++; | ||
110 | } | ||
111 | |||
112 | decode_pattern(src, dst, e, i, j, true, 1); | ||
113 | break; | ||
114 | |||
115 | case LONG_RUN_CODE: // 3 bytes | ||
116 | d = src[i++]; | ||
117 | e = ((c & ARGS_MASK) << 8) + (d + 0x42); | ||
118 | |||
119 | d = src[i++]; | ||
120 | d = ((d & 7) << 5) | ((d >> 3) & 0x1F); | ||
121 | |||
122 | decode_run(dst, e, static_cast<byte>(d), j); | ||
123 | break; | ||
124 | |||
125 | case SHORT_RUN_CODE: // 2 bytes | ||
126 | d = src[i++]; | ||
127 | d = ((d & 3) << 6) | ((d >> 2) & 0x3F); | ||
128 | |||
129 | e = (c & ARGS_MASK) + 2; | ||
130 | |||
131 | decode_run(dst, e, static_cast<byte>(d), j); | ||
132 | break; | ||
133 | }; | ||
134 | } while (i < srclen && j < dstlen); | ||
135 | |||
136 | return j; | ||
137 | } | ||
138 | |||
139 | namespace { | ||
140 | int encode_run(byte* dst, int& dstidx, byte val, int len, int dstlen) | ||
141 | { | ||
142 | if (len < 2) | ||
143 | throw std::invalid_argument("Length is too small."); | ||
144 | |||
145 | int ret = 0; | ||
146 | if (len <= 0x41) | ||
147 | { | ||
148 | if ((dstidx + 2) > dstlen) | ||
149 | throw std::runtime_error("Not enough space to store run."); | ||
150 | |||
151 | dst[dstidx++] = SHORT_RUN_CODE | (((len - 2) & ARGS_MASK)); | ||
152 | dst[dstidx++] = ((val >> 6) & 3) | ((val & 0x3F) << 2); | ||
153 | |||
154 | ret = 2; | ||
155 | } | ||
156 | else if (len <= 0x4041) | ||
157 | { | ||
158 | if ((dstidx + 3) > dstlen) | ||
159 | throw std::runtime_error("Not enough space to store run."); | ||
160 | |||
161 | byte b1 = (len - 0x42) >> 8; | ||
162 | byte b2 = (len - 0x42) & 0xFF; | ||
163 | |||
164 | dst[dstidx++] = LONG_RUN_CODE | ((b1 & ARGS_MASK)); | ||
165 | dst[dstidx++] = b2; | ||
166 | dst[dstidx++] = ((val >> 5) & 7) | ((val & 0x1F) << 3); | ||
167 | |||
168 | ret = 3; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | int long_count = len / 0x4041; | ||
173 | int short_len = len % 0x4041; | ||
174 | bool toosmall = short_len == 1; | ||
175 | |||
176 | int run_len = 0x4041; | ||
177 | for (int i = 0; i < long_count; i++) | ||
178 | { | ||
179 | if (toosmall && (i == (long_count-1))) | ||
180 | { | ||
181 | run_len--; | ||
182 | toosmall = false; | ||
183 | } | ||
184 | int tmp = encode_run(dst, dstidx, val, run_len, dstlen); | ||
185 | if (!tmp) return 0; | ||
186 | ret += tmp; | ||
187 | len -= run_len; | ||
188 | } | ||
189 | |||
190 | if (len) | ||
191 | { | ||
192 | int short_count = len / 0x41; | ||
193 | int short_rest = short_count ? (len % 0x41) : 0; | ||
194 | toosmall = short_rest == 1; | ||
195 | |||
196 | run_len = 0x41; | ||
197 | for (int i = 0; i < short_count; i++) | ||
198 | { | ||
199 | if (toosmall && (i == (short_count-1))) | ||
200 | { | ||
201 | run_len--; | ||
202 | toosmall = false; | ||
203 | } | ||
204 | int tmp = encode_run(dst, dstidx, val, run_len, dstlen); | ||
205 | if (!tmp) return 0; | ||
206 | ret += tmp; | ||
207 | len -= run_len; | ||
208 | } | ||
209 | int tmp = encode_run(dst, dstidx, val, len, dstlen); | ||
210 | if (!tmp) return 0; | ||
211 | ret += tmp; | ||
212 | len -= len; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | int encode_block(byte* dst, int& dstidx, byte* src, int& srcidx, int len, | ||
220 | int dstlen) | ||
221 | { | ||
222 | if (len < 1) | ||
223 | throw std::invalid_argument("Length is too small."); | ||
224 | |||
225 | int startidx = dstidx; | ||
226 | if (len < 0x21) | ||
227 | { | ||
228 | if ((dstidx + 2 + len) > dstlen) | ||
229 | throw std::runtime_error("Not enough space to store block."); | ||
230 | |||
231 | dst[dstidx++] = BLOCK_CODE | BLOCK_MODE | ((len - 1) & BLOCK_ARGS); | ||
232 | if ((dstidx ^ srcidx) & 1) | ||
233 | dst[dstidx++] = 0; | ||
234 | |||
235 | for (int i = 0; i < len; i++) | ||
236 | { | ||
237 | byte c = src[srcidx++]; | ||
238 | byte d = (c & 7) << 5; | ||
239 | c = (c & 0xF8) >> 3; | ||
240 | dst[dstidx++] = c | d; | ||
241 | } | ||
242 | } | ||
243 | else if (len < 0x2021) | ||
244 | { | ||
245 | if ((dstidx + 3 + len) > dstlen) | ||
246 | throw std::runtime_error("Not enough space to store block."); | ||
247 | |||
248 | dst[dstidx++] = BLOCK_CODE | (((len - 0x21) >> 8) & BLOCK_ARGS); | ||
249 | dst[dstidx++] = (len - 0x21) & 0xFF; | ||
250 | if ((dstidx ^ srcidx) & 1) | ||
251 | dst[dstidx++] = 0; | ||
252 | |||
253 | for (int i = 0; i < len; i++) | ||
254 | { | ||
255 | byte c = src[srcidx++]; | ||
256 | byte d = (c & 7) << 5; | ||
257 | c = (c & 0xF8) >> 3; | ||
258 | dst[dstidx++] = c | d; | ||
259 | } | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | int longblocks = len / 0x2020; | ||
264 | int rest = len % 0x2020; | ||
265 | for (int i = 0; i < longblocks; i++) | ||
266 | { | ||
267 | int tmp = encode_block(dst, dstidx, src, srcidx, 0x2020, dstlen); | ||
268 | if (!tmp) return 0; | ||
269 | } | ||
270 | if (rest) | ||
271 | { | ||
272 | int shortblocks = rest / 0x20; | ||
273 | for (int i = 0; i < shortblocks; i++) | ||
274 | { | ||
275 | int tmp = encode_block(dst, dstidx, src, srcidx, 0x20, dstlen); | ||
276 | if (!tmp) return 0; | ||
277 | } | ||
278 | rest = rest % 0x20; | ||
279 | int tmp = encode_block(dst, dstidx, src, srcidx, rest, dstlen); | ||
280 | if (!tmp) return 0; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | return (dstidx - startidx); | ||
285 | } | ||
286 | }; //namespace | ||
287 | |||
288 | int zen::cenc_encode(byte* src, int srclen, byte* dst, int dstlen) | ||
289 | { | ||
290 | if (!src || !srclen || !dst || !dstlen) | ||
291 | { | ||
292 | throw std::invalid_argument("Invalid argument(s)."); | ||
293 | } | ||
294 | |||
295 | int i = 0, j = 0, k = 0; | ||
296 | word c, d, e; | ||
297 | int runlen = 0; | ||
298 | while (i < srclen && j < dstlen) | ||
299 | { | ||
300 | k = i; | ||
301 | c = src[i++]; | ||
302 | runlen = 1; | ||
303 | while (i < srclen && src[i] == c) | ||
304 | { | ||
305 | runlen++; | ||
306 | i++; | ||
307 | } | ||
308 | if (runlen >= 2) | ||
309 | { | ||
310 | if (!encode_run(dst, j, c, runlen, dstlen)) | ||
311 | return 0; | ||
312 | } | ||
313 | else | ||
314 | { | ||
315 | runlen = 0; | ||
316 | i = k; | ||
317 | while (i < (srclen - 1) && (src[i] != src[i + 1])) | ||
318 | { | ||
319 | runlen++; | ||
320 | i++; | ||
321 | } | ||
322 | if (i == (srclen - 1)) | ||
323 | { | ||
324 | runlen++; | ||
325 | i++; | ||
326 | } | ||
327 | if (!encode_block(dst, j, src, k, runlen, dstlen)) | ||
328 | return 0; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | return j; | ||
333 | } | ||
diff --git a/utils/zenutils/source/shared/cenc.h b/utils/zenutils/source/shared/cenc.h new file mode 100755 index 0000000000..12a7c92516 --- /dev/null +++ b/utils/zenutils/source/shared/cenc.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef ZEN_CENC_H_INCLUDED | ||
20 | #define ZEN_CENC_H_INCLUDED | ||
21 | |||
22 | #include <utils.h> | ||
23 | |||
24 | namespace zen { | ||
25 | int cenc_decode(byte* src, int srclen, byte* dst, int dstlen); | ||
26 | int cenc_encode(byte* src, int srclen, byte* dst, int dstlen); | ||
27 | }; //namespace zen | ||
28 | |||
29 | #endif //CENC_H_INCLUDED | ||
diff --git a/utils/zenutils/source/shared/crypt.cpp b/utils/zenutils/source/shared/crypt.cpp new file mode 100755 index 0000000000..9c2d33870c --- /dev/null +++ b/utils/zenutils/source/shared/crypt.cpp | |||
@@ -0,0 +1,91 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include "crypt.h" | ||
20 | #include <stdexcept> | ||
21 | #include <beecrypt/hmacsha1.h> | ||
22 | #include <beecrypt/blockmode.h> | ||
23 | #include <beecrypt/blowfish.h> | ||
24 | |||
25 | |||
26 | bool zen::hmac_sha1_calc(const byte* key, size_t keylen, const byte* data, | ||
27 | size_t datalen, byte* sig, size_t* siglen) | ||
28 | { | ||
29 | hmacsha1Param param; | ||
30 | if (hmacsha1Setup(¶m, key, keylen * 8)) | ||
31 | return false; | ||
32 | if (hmacsha1Update(¶m, data, datalen)) | ||
33 | return false; | ||
34 | if (hmacsha1Digest(¶m, sig)) | ||
35 | return false; | ||
36 | return true; | ||
37 | } | ||
38 | |||
39 | bool zen::bf_cbc_encrypt(const byte* key, size_t keylen, byte* data, | ||
40 | size_t datalen, const byte* iv) | ||
41 | { | ||
42 | if (datalen % blowfish.blocksize) | ||
43 | throw std::invalid_argument( | ||
44 | "The length must be aligned on a 8 byte boundary."); | ||
45 | |||
46 | blowfishParam param; | ||
47 | if (blowfishSetup(¶m, key, keylen * 8, ENCRYPT)) | ||
48 | return false; | ||
49 | if (blowfishSetIV(¶m, iv)) | ||
50 | return false; | ||
51 | |||
52 | byte* plain = new byte[datalen]; | ||
53 | memcpy(plain, data, datalen); | ||
54 | |||
55 | unsigned int nblocks = datalen / blowfish.blocksize; | ||
56 | if (blockEncryptCBC(&blowfish, ¶m, (uint32_t*)data, (uint32_t*)plain, | ||
57 | nblocks)) | ||
58 | { | ||
59 | delete [] plain; | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | return true; | ||
64 | } | ||
65 | |||
66 | bool zen::bf_cbc_decrypt(const byte* key, size_t keylen, byte* data, | ||
67 | size_t datalen, const byte* iv) | ||
68 | { | ||
69 | if (datalen % blowfish.blocksize) | ||
70 | throw std::invalid_argument( | ||
71 | "The length must be aligned on a 8 byte boundary."); | ||
72 | |||
73 | blowfishParam param; | ||
74 | if (blowfishSetup(¶m, key, keylen * 8, ENCRYPT)) | ||
75 | return false; | ||
76 | if (blowfishSetIV(¶m, iv)) | ||
77 | return false; | ||
78 | |||
79 | byte* cipher = new byte[datalen]; | ||
80 | memcpy(cipher, data, datalen); | ||
81 | |||
82 | unsigned int nblocks = datalen / blowfish.blocksize; | ||
83 | if (blockDecryptCBC(&blowfish, ¶m, (uint32_t*)data, (uint32_t*)cipher, | ||
84 | nblocks)) | ||
85 | { | ||
86 | delete [] cipher; | ||
87 | return false; | ||
88 | } | ||
89 | |||
90 | return true; | ||
91 | } | ||
diff --git a/utils/zenutils/source/shared/crypt.h b/utils/zenutils/source/shared/crypt.h new file mode 100755 index 0000000000..a057055b70 --- /dev/null +++ b/utils/zenutils/source/shared/crypt.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef ZEN_CRYPT_H_INCLUDED | ||
20 | #define ZEN_CRYPT_H_INCLUDED | ||
21 | |||
22 | #include <utils.h> | ||
23 | |||
24 | namespace zen { | ||
25 | bool hmac_sha1_calc(const byte* key, size_t keylen, const byte* data, size_t datalen, byte* sig, size_t* siglen); | ||
26 | bool bf_cbc_encrypt(const byte* key, size_t keylen, byte* data, size_t datalen, const byte* iv); | ||
27 | bool bf_cbc_decrypt(const byte* key, size_t keylen, byte* data, size_t datalen, const byte* iv); | ||
28 | }; //namespace zen | ||
29 | |||
30 | #endif //ZEN_CRYPT_H_INCLUDED | ||
diff --git a/utils/zenutils/source/shared/file.cpp b/utils/zenutils/source/shared/file.cpp new file mode 100755 index 0000000000..2c31498972 --- /dev/null +++ b/utils/zenutils/source/shared/file.cpp | |||
@@ -0,0 +1,106 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include "file.h" | ||
20 | #include <fstream> | ||
21 | |||
22 | |||
23 | bool shared::read_file(const std::string& filename, bytes& buffer, | ||
24 | std::streampos offset, std::streamsize count) | ||
25 | { | ||
26 | std::ifstream ifs; | ||
27 | ifs.open(filename.c_str(), std::ios::binary); | ||
28 | if (!ifs) | ||
29 | { | ||
30 | return false; | ||
31 | } | ||
32 | |||
33 | std::ifstream::pos_type startpos = offset; | ||
34 | ifs.seekg(offset, std::ios::beg); | ||
35 | if (count == -1) | ||
36 | ifs.seekg(0, std::ios::end); | ||
37 | else | ||
38 | ifs.seekg(count, std::ios::cur); | ||
39 | std::ifstream::pos_type endpos = ifs.tellg(); | ||
40 | |||
41 | buffer.resize(endpos-startpos); | ||
42 | ifs.seekg(offset, std::ios::beg); | ||
43 | |||
44 | ifs.read((char*)&buffer[0], endpos-startpos); | ||
45 | |||
46 | ifs.close(); | ||
47 | return ifs.good(); | ||
48 | } | ||
49 | |||
50 | |||
51 | bool shared::write_file(const std::string& filename, bytes& buffer, | ||
52 | bool truncate, std::streampos offset, | ||
53 | std::streamsize count) | ||
54 | { | ||
55 | std::ios::openmode mode = std::ios::in|std::ios::out|std::ios::binary; | ||
56 | if (truncate) | ||
57 | mode |= std::ios::trunc; | ||
58 | |||
59 | std::fstream ofs; | ||
60 | ofs.open(filename.c_str(), mode); | ||
61 | if (!ofs) | ||
62 | { | ||
63 | return false; | ||
64 | } | ||
65 | |||
66 | if (count == -1) | ||
67 | count = buffer.size(); | ||
68 | else if (count > buffer.size()) | ||
69 | return false; | ||
70 | |||
71 | ofs.seekg(offset, std::ios::beg); | ||
72 | |||
73 | ofs.write((char*)&buffer[0], count); | ||
74 | |||
75 | ofs.close(); | ||
76 | return ofs.good(); | ||
77 | } | ||
78 | |||
79 | bool shared::file_exists(const std::string& filename) | ||
80 | { | ||
81 | std::ifstream ifs; | ||
82 | ifs.open(filename.c_str(), std::ios::in); | ||
83 | if (ifs.is_open()) | ||
84 | { | ||
85 | ifs.close(); | ||
86 | return true; | ||
87 | } | ||
88 | return false; | ||
89 | } | ||
90 | |||
91 | bool shared::copy_file(const std::string& srcname, const std::string& dstname) | ||
92 | { | ||
93 | bytes buffer; | ||
94 | if (!read_file(srcname, buffer)) | ||
95 | return false; | ||
96 | return write_file(dstname, buffer, true); | ||
97 | } | ||
98 | |||
99 | bool shared::backup_file(const std::string& filename, bool force) | ||
100 | { | ||
101 | std::string backupname = filename + ".bak"; | ||
102 | if (!force) | ||
103 | if (file_exists(backupname)) | ||
104 | return true; | ||
105 | return copy_file(filename, backupname); | ||
106 | } | ||
diff --git a/utils/zenutils/source/shared/file.h b/utils/zenutils/source/shared/file.h new file mode 100755 index 0000000000..8fa533c981 --- /dev/null +++ b/utils/zenutils/source/shared/file.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef SHARED_FILE_H_INCLUDED | ||
20 | #define SHARED_FILE_H_INCLUDED | ||
21 | |||
22 | #include <string> | ||
23 | #include <iostream> | ||
24 | #include "utils.h" | ||
25 | |||
26 | namespace shared { | ||
27 | bool read_file(const std::string& filename, bytes& buffer, | ||
28 | std::streampos offset = 0, std::streamsize count = -1); | ||
29 | bool write_file(const std::string& filename, bytes& buffer, bool truncate, | ||
30 | std::streampos offset = 0, std::streamsize count = -1); | ||
31 | bool file_exists(const std::string& filename); | ||
32 | bool copy_file(const std::string& srcname, const std::string& dstname); | ||
33 | bool backup_file(const std::string& filename, bool force = false); | ||
34 | }; //namespace shared | ||
35 | |||
36 | #endif //SHARED_FILE_H_INCLUDED | ||
diff --git a/utils/zenutils/source/shared/firmware.cpp b/utils/zenutils/source/shared/firmware.cpp new file mode 100755 index 0000000000..7767b55d8f --- /dev/null +++ b/utils/zenutils/source/shared/firmware.cpp | |||
@@ -0,0 +1,387 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include "firmware.h" | ||
20 | #include <iostream> | ||
21 | #include <stdexcept> | ||
22 | |||
23 | |||
24 | zen::firmware_entry::firmware_entry(bool big_endian) | ||
25 | : _big_endian(big_endian) | ||
26 | { | ||
27 | } | ||
28 | |||
29 | zen::firmware_entry::firmware_entry(const firmware_entry& copy) | ||
30 | { | ||
31 | assign(copy); | ||
32 | } | ||
33 | |||
34 | zen::firmware_entry& zen::firmware_entry::operator=(const firmware_entry& right) | ||
35 | { | ||
36 | assign(right); | ||
37 | return *this; | ||
38 | } | ||
39 | |||
40 | |||
41 | bool zen::firmware_entry::read(std::istream& is) | ||
42 | { | ||
43 | // Read the header. | ||
44 | is.read((char*)&_header, sizeof(firmware_header_t)); | ||
45 | if (!is.good()) | ||
46 | return false; | ||
47 | |||
48 | // If the firmware is big-endian, swap the header values to little-endian. | ||
49 | if (_big_endian) | ||
50 | { | ||
51 | _header.tag = shared::swap(_header.tag); | ||
52 | if (_header.tag != 'NULL') | ||
53 | { | ||
54 | _header.size = shared::swap(_header.size); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | // Resize the bytes buffer to the size specified in the header. | ||
59 | _bytes.resize(_header.size); | ||
60 | |||
61 | // Read the entry contents. | ||
62 | is.read(reinterpret_cast<char*>(&_bytes[0]), | ||
63 | _header.size); | ||
64 | |||
65 | return is.good(); | ||
66 | } | ||
67 | |||
68 | bool zen::firmware_entry::write(std::ostream& os) const | ||
69 | { | ||
70 | // Form a header using the current size of the bytes buffer. | ||
71 | firmware_header_t header = { | ||
72 | _header.tag, | ||
73 | static_cast<dword>(_bytes.size()) | ||
74 | }; | ||
75 | |||
76 | // If the firmware is big-endian, swap the header values back into big-endian. | ||
77 | if (_big_endian) | ||
78 | { | ||
79 | if (header.tag != 'NULL') | ||
80 | { | ||
81 | header.size = shared::swap(header.size); | ||
82 | } | ||
83 | header.tag = shared::swap(header.tag); | ||
84 | } | ||
85 | |||
86 | // Write the header. | ||
87 | os.write((const char*)&header, sizeof(firmware_header_t)); | ||
88 | if (!os.good()) | ||
89 | return false; | ||
90 | |||
91 | // Write the entry contents. | ||
92 | os.write(reinterpret_cast<const char*>(&_bytes[0]), | ||
93 | static_cast<std::streamsize>(_bytes.size())); | ||
94 | |||
95 | return os.good(); | ||
96 | } | ||
97 | |||
98 | |||
99 | bool zen::firmware_entry::is_big_endian() const | ||
100 | { | ||
101 | return _big_endian; | ||
102 | } | ||
103 | |||
104 | const zen::firmware_header_t& zen::firmware_entry::get_header() const | ||
105 | { | ||
106 | return _header; | ||
107 | } | ||
108 | zen::firmware_header_t& zen::firmware_entry::get_header() | ||
109 | { | ||
110 | return _header; | ||
111 | } | ||
112 | |||
113 | const shared::bytes& zen::firmware_entry::get_bytes() const | ||
114 | { | ||
115 | return _bytes; | ||
116 | } | ||
117 | shared::bytes& zen::firmware_entry::get_bytes() | ||
118 | { | ||
119 | return _bytes; | ||
120 | } | ||
121 | |||
122 | |||
123 | std::string zen::firmware_entry::get_name() const | ||
124 | { | ||
125 | char name[5]; | ||
126 | *(dword*)name = shared::swap(_header.tag); | ||
127 | name[4] = '\0'; | ||
128 | |||
129 | // Determine if all characters in the tag are printable. | ||
130 | bool isprintable = true; | ||
131 | for (int i = 0; i < 4; i++) | ||
132 | { | ||
133 | if (!isprint((byte)name[i])) | ||
134 | { | ||
135 | isprintable = false; | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | // If they are, simply return the tag as a string. | ||
141 | if (isprintable) | ||
142 | { | ||
143 | return std::string(name); | ||
144 | } | ||
145 | |||
146 | // Otherwise, encode the tag into a hexadecimal string. | ||
147 | char buffer[11]; | ||
148 | sprintf(buffer, "0x%08x", _header.tag); | ||
149 | return std::string(buffer); | ||
150 | } | ||
151 | |||
152 | std::string zen::firmware_entry::get_content_name() const | ||
153 | { | ||
154 | std::string name = get_name(); | ||
155 | if (name == "DATA") | ||
156 | { | ||
157 | name = ""; | ||
158 | int nameoff = is_big_endian() ? 1 : 0; | ||
159 | for (int i = 0; i < 16; i++) | ||
160 | { | ||
161 | char c = get_bytes()[i * 2 + nameoff]; | ||
162 | if (!c) | ||
163 | break; | ||
164 | name += c; | ||
165 | } | ||
166 | } | ||
167 | else if (name == "EXT0") | ||
168 | { | ||
169 | name = ""; | ||
170 | int nameoff = is_big_endian() ? 1 : 0; | ||
171 | for (int i = 0; i < 12; i++) | ||
172 | { | ||
173 | char c = get_bytes()[i * 2 + nameoff]; | ||
174 | if (!c) | ||
175 | break; | ||
176 | name += c; | ||
177 | } | ||
178 | } | ||
179 | return name; | ||
180 | } | ||
181 | |||
182 | size_t zen::firmware_entry::get_content_offset() const | ||
183 | { | ||
184 | std::string name = get_name(); | ||
185 | if (name == "DATA") | ||
186 | { | ||
187 | return 32; | ||
188 | } | ||
189 | else if (name == "EXT0") | ||
190 | { | ||
191 | return 24; | ||
192 | } | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | size_t zen::firmware_entry::calc_size() const | ||
197 | { | ||
198 | return _bytes.size() + sizeof(firmware_header_t); | ||
199 | } | ||
200 | |||
201 | |||
202 | void zen::firmware_entry::assign(const firmware_entry& copy) | ||
203 | { | ||
204 | _big_endian = copy._big_endian; | ||
205 | _header.tag = copy._header.tag; | ||
206 | _header.size = copy._header.size; | ||
207 | _bytes.assign(copy._bytes.begin(), copy._bytes.end()); | ||
208 | } | ||
209 | |||
210 | |||
211 | |||
212 | zen::firmware_archive::firmware_archive(bool big_endian) | ||
213 | : _big_endian(big_endian) | ||
214 | { | ||
215 | } | ||
216 | |||
217 | zen::firmware_archive::firmware_archive(const firmware_archive& copy) | ||
218 | { | ||
219 | assign(copy); | ||
220 | } | ||
221 | |||
222 | zen::firmware_archive& zen::firmware_archive::operator=(const firmware_archive& right) | ||
223 | { | ||
224 | assign(right); | ||
225 | return *this; | ||
226 | } | ||
227 | |||
228 | |||
229 | bool zen::firmware_archive::read(std::istream& is) | ||
230 | { | ||
231 | // Read the root entry's header. | ||
232 | firmware_header_t root; | ||
233 | is.read((char*)&root, sizeof(firmware_header_t)); | ||
234 | if (!is.good()) | ||
235 | return false; | ||
236 | |||
237 | if ((root.tag != 'CIFF') && (root.tag != 'FFIC')) | ||
238 | { | ||
239 | throw std::runtime_error("Invalid firmware archive format!"); | ||
240 | } | ||
241 | |||
242 | _big_endian = root.tag == 'FFIC' ? true : false; | ||
243 | if (_big_endian) | ||
244 | { | ||
245 | root.tag = shared::swap(root.tag); | ||
246 | root.size = shared::swap(root.size); | ||
247 | } | ||
248 | |||
249 | // Save the current stream position. | ||
250 | std::istream::pos_type endpos = is.tellg(); | ||
251 | std::istream::pos_type curpos = endpos; | ||
252 | endpos += std::istream::pos_type(root.size); | ||
253 | |||
254 | // Read untill the end of the root entry contents. | ||
255 | while (curpos < endpos) | ||
256 | { | ||
257 | firmware_entry entry(_big_endian); | ||
258 | if (!entry.read(is)) | ||
259 | return false; | ||
260 | |||
261 | _children.push_back(entry); | ||
262 | curpos = is.tellg(); | ||
263 | } | ||
264 | |||
265 | curpos = is.tellg(); | ||
266 | is.seekg(0, std::ios::end); | ||
267 | endpos = is.tellg(); | ||
268 | is.seekg(curpos); | ||
269 | |||
270 | // Read untill the end of the file. | ||
271 | while (((size_t)curpos + sizeof(firmware_header_t)) < endpos) | ||
272 | { | ||
273 | firmware_entry entry(_big_endian); | ||
274 | if (!entry.read(is)) | ||
275 | return false; | ||
276 | |||
277 | _neighbours.push_back(entry); | ||
278 | curpos = is.tellg(); | ||
279 | } | ||
280 | |||
281 | return true; | ||
282 | } | ||
283 | |||
284 | bool zen::firmware_archive::write(std::ostream& os) const | ||
285 | { | ||
286 | // Read the root entry's header. | ||
287 | firmware_header_t root = {'CIFF', 0}; | ||
288 | |||
289 | // Calculate the total size of all the children entries. | ||
290 | for (firmware_entries::const_iterator i = _children.begin(); | ||
291 | i != _children.end(); ++i) | ||
292 | { | ||
293 | root.size += i->calc_size(); | ||
294 | } | ||
295 | |||
296 | // If the firmware is big-endian, swap the header values back into big-endian. | ||
297 | if (_big_endian) | ||
298 | { | ||
299 | root.tag = shared::swap(root.tag); | ||
300 | root.size = shared::swap(root.size); | ||
301 | } | ||
302 | |||
303 | // Write the header. | ||
304 | os.write((const char*)&root, sizeof(firmware_header_t)); | ||
305 | if (!os.good()) | ||
306 | return false; | ||
307 | |||
308 | // Write all the child entries. | ||
309 | for (firmware_entries::const_iterator i = _children.begin(); | ||
310 | i != _children.end(); ++i) | ||
311 | { | ||
312 | if (!i->write(os)) | ||
313 | return false; | ||
314 | } | ||
315 | |||
316 | // Write all the neighbour entries. | ||
317 | for (firmware_entries::const_iterator i = _neighbours.begin(); | ||
318 | i != _neighbours.end(); ++i) | ||
319 | { | ||
320 | if (!i->write(os)) | ||
321 | return false; | ||
322 | } | ||
323 | |||
324 | return true; | ||
325 | } | ||
326 | |||
327 | |||
328 | bool zen::firmware_archive::is_big_endian() const | ||
329 | { | ||
330 | return _big_endian; | ||
331 | } | ||
332 | |||
333 | const zen::firmware_entries& zen::firmware_archive::get_children() const | ||
334 | { | ||
335 | return _children; | ||
336 | } | ||
337 | zen::firmware_entries& zen::firmware_archive::get_children() | ||
338 | { | ||
339 | return _children; | ||
340 | } | ||
341 | |||
342 | const zen::firmware_entries& zen::firmware_archive::get_neighbours() const | ||
343 | { | ||
344 | return _neighbours; | ||
345 | } | ||
346 | zen::firmware_entries& zen::firmware_archive::get_neighbours() | ||
347 | { | ||
348 | return _neighbours; | ||
349 | } | ||
350 | |||
351 | bool zen::firmware_archive::is_signed() const | ||
352 | { | ||
353 | for (firmware_entries::const_iterator i = _neighbours.begin(); | ||
354 | i != _neighbours.end(); i++) | ||
355 | { | ||
356 | if (i->get_name() == "NULL") | ||
357 | return true; | ||
358 | } | ||
359 | return false; | ||
360 | } | ||
361 | |||
362 | size_t zen::firmware_archive::calc_size() const | ||
363 | { | ||
364 | size_t size = sizeof(firmware_header_t); | ||
365 | |||
366 | for (firmware_entries::const_iterator i = _children.begin(); | ||
367 | i != _children.end(); i++) | ||
368 | { | ||
369 | size += i->calc_size(); | ||
370 | } | ||
371 | |||
372 | for (firmware_entries::const_iterator i = _neighbours.begin(); | ||
373 | i != _neighbours.end(); i++) | ||
374 | { | ||
375 | size += i->calc_size(); | ||
376 | } | ||
377 | |||
378 | return size; | ||
379 | } | ||
380 | |||
381 | |||
382 | void zen::firmware_archive::assign(const firmware_archive& copy) | ||
383 | { | ||
384 | _big_endian = copy._big_endian; | ||
385 | _children.assign(copy._children.begin(), copy._children.end()); | ||
386 | _neighbours.assign(copy._neighbours.begin(), copy._neighbours.end()); | ||
387 | } | ||
diff --git a/utils/zenutils/source/shared/firmware.h b/utils/zenutils/source/shared/firmware.h new file mode 100755 index 0000000000..3542186590 --- /dev/null +++ b/utils/zenutils/source/shared/firmware.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef ZEN_FIRMWARE_H_INCLUDED | ||
20 | #define ZEN_FIRMWARE_H_INCLUDED | ||
21 | |||
22 | #include <list> | ||
23 | #include <utils.h> | ||
24 | |||
25 | namespace zen { | ||
26 | struct firmware_header_t | ||
27 | { | ||
28 | dword tag; | ||
29 | dword size; | ||
30 | }; //struct firmware_header_t | ||
31 | |||
32 | class firmware_entry | ||
33 | { | ||
34 | public: | ||
35 | firmware_entry(bool big_endian); | ||
36 | firmware_entry(const firmware_entry& copy); | ||
37 | firmware_entry& operator=(const firmware_entry& right); | ||
38 | |||
39 | bool read(std::istream& is); | ||
40 | bool write(std::ostream& os) const; | ||
41 | |||
42 | bool is_big_endian() const; | ||
43 | const firmware_header_t& get_header() const; | ||
44 | firmware_header_t& get_header(); | ||
45 | const shared::bytes& get_bytes() const; | ||
46 | shared::bytes& get_bytes(); | ||
47 | |||
48 | std::string get_name() const; | ||
49 | std::string get_content_name() const; | ||
50 | size_t get_content_offset() const; | ||
51 | size_t calc_size() const; | ||
52 | |||
53 | protected: | ||
54 | void assign(const firmware_entry& copy); | ||
55 | |||
56 | private: | ||
57 | bool _big_endian; | ||
58 | firmware_header_t _header; | ||
59 | shared::bytes _bytes; | ||
60 | }; //class firmware_entry | ||
61 | |||
62 | typedef std::list<firmware_entry> firmware_entries; | ||
63 | |||
64 | class firmware_archive | ||
65 | { | ||
66 | public: | ||
67 | firmware_archive(bool big_endian); | ||
68 | firmware_archive(const firmware_archive& copy); | ||
69 | firmware_archive& operator=(const firmware_archive& right); | ||
70 | |||
71 | bool read(std::istream& is); | ||
72 | bool write(std::ostream& os) const; | ||
73 | |||
74 | bool is_big_endian() const; | ||
75 | const firmware_entries& get_children() const; | ||
76 | firmware_entries& get_children(); | ||
77 | const firmware_entries& get_neighbours() const; | ||
78 | firmware_entries& get_neighbours(); | ||
79 | bool is_signed() const; | ||
80 | size_t calc_size() const; | ||
81 | |||
82 | protected: | ||
83 | void assign(const firmware_archive& copy); | ||
84 | |||
85 | private: | ||
86 | firmware_entries _children; | ||
87 | firmware_entries _neighbours; | ||
88 | bool _big_endian; | ||
89 | }; //class firmware_archive | ||
90 | }; //namespace zen | ||
91 | |||
92 | #endif //ZEN_FIRMWARE_ARCHIVE_H_INCLUDED | ||
diff --git a/utils/zenutils/source/shared/pe.cpp b/utils/zenutils/source/shared/pe.cpp new file mode 100755 index 0000000000..c86ec6c8cc --- /dev/null +++ b/utils/zenutils/source/shared/pe.cpp | |||
@@ -0,0 +1,128 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include "pe.h" | ||
20 | |||
21 | |||
22 | shared::pe_file::pe_file(PeLib::PeFile* pef) : _pef(pef) | ||
23 | { | ||
24 | } | ||
25 | shared::pe_file::~pe_file() | ||
26 | { | ||
27 | if (_pef != NULL) | ||
28 | delete _pef; | ||
29 | } | ||
30 | |||
31 | bool shared::pe_file::is_valid() const | ||
32 | { | ||
33 | if (_pef->getBits() == 32) | ||
34 | { | ||
35 | PeLib::PeHeader32& pef32 = static_cast<PeLib::PeFile32*>(_pef)->peHeader(); | ||
36 | if (!pef32.isValid()) | ||
37 | return false; | ||
38 | return true; | ||
39 | } | ||
40 | else if (_pef->getBits() == 64) | ||
41 | { | ||
42 | PeLib::PeHeader64& pef64 = static_cast<PeLib::PeFile64*>(_pef)->peHeader(); | ||
43 | if (!pef64.isValid()) | ||
44 | return false; | ||
45 | return true; | ||
46 | } | ||
47 | return false; | ||
48 | } | ||
49 | |||
50 | bool shared::pe_file::read(const std::string& filename) | ||
51 | { | ||
52 | if (_pef != NULL) | ||
53 | { | ||
54 | delete _pef; | ||
55 | _pef = NULL; | ||
56 | } | ||
57 | |||
58 | _pef = PeLib::openPeFile(filename); | ||
59 | if (!_pef) | ||
60 | { | ||
61 | return false; | ||
62 | } | ||
63 | if (_pef->readMzHeader()) | ||
64 | { | ||
65 | delete _pef; | ||
66 | return false; | ||
67 | } | ||
68 | if (!_pef->mzHeader().isValid()) | ||
69 | { | ||
70 | delete _pef; | ||
71 | return false; | ||
72 | } | ||
73 | if (_pef->readPeHeader()) | ||
74 | { | ||
75 | delete _pef; | ||
76 | return false; | ||
77 | } | ||
78 | if (!is_valid()) | ||
79 | { | ||
80 | delete _pef; | ||
81 | return false; | ||
82 | } | ||
83 | return true; | ||
84 | } | ||
85 | |||
86 | bool shared::pe_file::find_section(const std::string& name, section_info& info) const | ||
87 | { | ||
88 | if (_pef->getBits() == 32) | ||
89 | return find_section(static_cast<PeLib::PeFile32*>(_pef), | ||
90 | name, info); | ||
91 | else if (_pef->getBits() == 64) | ||
92 | return find_section(static_cast<PeLib::PeFile64*>(_pef), | ||
93 | name, info); | ||
94 | return false; | ||
95 | } | ||
96 | |||
97 | bool shared::pe_file::add_section(const std::string& name, | ||
98 | const bytes& buffer, section_info& info) | ||
99 | { | ||
100 | if (_pef->getBits() == 32) | ||
101 | { | ||
102 | return add_section(static_cast<PeLib::PeFile32*>(_pef), | ||
103 | name, buffer, info); | ||
104 | } | ||
105 | else if (_pef->getBits() == 64) | ||
106 | { | ||
107 | return add_section(static_cast<PeLib::PeFile64*>(_pef), | ||
108 | name, buffer, info); | ||
109 | } | ||
110 | return false; | ||
111 | } | ||
112 | |||
113 | dword shared::pe_file::get_image_base() const | ||
114 | { | ||
115 | if (_pef->getBits() == 32) | ||
116 | return static_cast<PeLib::PeFile32*>(_pef)->peHeader().getImageBase(); | ||
117 | else | ||
118 | return static_cast<PeLib::PeFile64*>(_pef)->peHeader().getImageBase(); | ||
119 | return 0; | ||
120 | } | ||
121 | dword shared::pe_file::pa_to_va(dword pa) const | ||
122 | { | ||
123 | if (_pef->getBits() == 32) | ||
124 | return static_cast<PeLib::PeFile32*>(_pef)->peHeader().offsetToVa(pa); | ||
125 | else | ||
126 | return static_cast<PeLib::PeFile64*>(_pef)->peHeader().offsetToVa(pa); | ||
127 | return 0; | ||
128 | } | ||
diff --git a/utils/zenutils/source/shared/pe.h b/utils/zenutils/source/shared/pe.h new file mode 100755 index 0000000000..92a272d3c7 --- /dev/null +++ b/utils/zenutils/source/shared/pe.h | |||
@@ -0,0 +1,142 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef SHARED_PE_H_INCLUDED | ||
20 | #define SHARED_PE_H_INCLUDED | ||
21 | |||
22 | #include <string> | ||
23 | #include <pelib/PeLib.h> | ||
24 | #include <utils.h> | ||
25 | |||
26 | namespace shared { | ||
27 | struct section_info | ||
28 | { | ||
29 | word index; | ||
30 | dword virtual_address; | ||
31 | dword virtual_size; | ||
32 | dword raw_address; | ||
33 | dword raw_size; | ||
34 | dword characteristics; | ||
35 | }; //struct section_info | ||
36 | |||
37 | class pe_file | ||
38 | { | ||
39 | public: | ||
40 | pe_file(PeLib::PeFile* pef = NULL); | ||
41 | ~pe_file(); | ||
42 | |||
43 | bool is_valid() const; | ||
44 | bool read(const std::string& filename); | ||
45 | bool find_section(const std::string& name, section_info& info) const; | ||
46 | bool add_section(const std::string& name, const bytes& buffer, section_info& info); | ||
47 | dword get_image_base() const; | ||
48 | dword pa_to_va(PeLib::dword pa) const; | ||
49 | |||
50 | protected: | ||
51 | template <int _Bits> | ||
52 | static bool find_section(const PeLib::PeFileT<_Bits>* pef, | ||
53 | const std::string& name, section_info& info); | ||
54 | template <int _Bits> | ||
55 | static bool add_section(PeLib::PeFileT<_Bits>* pef, | ||
56 | const std::string& name, const bytes& buffer, | ||
57 | section_info& info); | ||
58 | |||
59 | private: | ||
60 | PeLib::PeFile* _pef; | ||
61 | }; //class pe_file | ||
62 | |||
63 | |||
64 | template <int _Bits> | ||
65 | bool pe_file::find_section(const PeLib::PeFileT<_Bits>* pef, | ||
66 | const std::string& name, section_info& info) | ||
67 | { | ||
68 | for (PeLib::word i = 0; i < pef->peHeader().getNumberOfSections(); i++) | ||
69 | { | ||
70 | if (pef->peHeader().getSectionName(i) == name) | ||
71 | { | ||
72 | info.index = i; | ||
73 | info.virtual_address = pef->peHeader().getVirtualAddress(i); | ||
74 | info.virtual_size = pef->peHeader().getVirtualSize(i); | ||
75 | info.raw_address = pef->peHeader().getPointerToRawData(i); | ||
76 | info.raw_size = pef->peHeader().getSizeOfRawData(i); | ||
77 | info.characteristics = pef->peHeader().getCharacteristics(i); | ||
78 | return true; | ||
79 | } | ||
80 | } | ||
81 | return false; | ||
82 | } | ||
83 | |||
84 | template <int _Bits> | ||
85 | bool pe_file::add_section(PeLib::PeFileT<_Bits>* pef, | ||
86 | const std::string& name, const bytes& buffer, | ||
87 | section_info& info) | ||
88 | { | ||
89 | using namespace PeLib; | ||
90 | |||
91 | // Check if the last section has the same name as the one being added. | ||
92 | PeLib::word secnum = pef->peHeader().getNumberOfSections(); | ||
93 | if (pef->peHeader().getSectionName(secnum-1) == name) | ||
94 | { | ||
95 | // If it is, we change the attributes of the existing section. | ||
96 | secnum = secnum - 1; | ||
97 | pef->peHeader().setSizeOfRawData(secnum, | ||
98 | alignOffset(buffer.size(), | ||
99 | pef->peHeader().getFileAlignment())); | ||
100 | pef->peHeader().setVirtualSize(secnum, | ||
101 | alignOffset(buffer.size(), | ||
102 | pef->peHeader().getSectionAlignment())); | ||
103 | PeLib::dword chars = pef->peHeader().getCharacteristics(secnum-1); | ||
104 | pef->peHeader().setCharacteristics(secnum, | ||
105 | chars | PELIB_IMAGE_SCN_MEM_WRITE | PELIB_IMAGE_SCN_MEM_READ); | ||
106 | } | ||
107 | else | ||
108 | { | ||
109 | // Otherwise we add a new section. | ||
110 | if (pef->peHeader().addSection(name, buffer.size()) != NO_ERROR) | ||
111 | { | ||
112 | return false; | ||
113 | } | ||
114 | pef->peHeader().makeValid(pef->mzHeader().getAddressOfPeHeader()); | ||
115 | pef->peHeader().write(pef->getFileName(), pef->mzHeader().getAddressOfPeHeader()); | ||
116 | } | ||
117 | |||
118 | // Save the section headers to the file. | ||
119 | if (pef->peHeader().writeSections(pef->getFileName()) != NO_ERROR) | ||
120 | { | ||
121 | return false; | ||
122 | } | ||
123 | |||
124 | // Save the section data to the file. | ||
125 | if (pef->peHeader().writeSectionData(pef->getFileName(), secnum, buffer) != NO_ERROR) | ||
126 | { | ||
127 | return false; | ||
128 | } | ||
129 | |||
130 | // Fill out the section information. | ||
131 | info.index = secnum; | ||
132 | info.virtual_address = pef->peHeader().getVirtualAddress(secnum); | ||
133 | info.virtual_size = pef->peHeader().getVirtualSize(secnum); | ||
134 | info.raw_address = pef->peHeader().getPointerToRawData(secnum); | ||
135 | info.raw_size = pef->peHeader().getSizeOfRawData(secnum); | ||
136 | info.characteristics = pef->peHeader().getCharacteristics(secnum); | ||
137 | |||
138 | return true; | ||
139 | } | ||
140 | }; //namespace shared | ||
141 | |||
142 | #endif //SHARED_PE_H_INCLUDED | ||
diff --git a/utils/zenutils/source/shared/shared.cpp b/utils/zenutils/source/shared/shared.cpp new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/utils/zenutils/source/shared/shared.cpp | |||
diff --git a/utils/zenutils/source/shared/updater.cpp b/utils/zenutils/source/shared/updater.cpp new file mode 100755 index 0000000000..77d3f2876c --- /dev/null +++ b/utils/zenutils/source/shared/updater.cpp | |||
@@ -0,0 +1,151 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include "updater.h" | ||
20 | #include <file.h> | ||
21 | #include <pe.h> | ||
22 | #include <utils.h> | ||
23 | |||
24 | |||
25 | const char* zen::find_firmware_key(const byte* buffer, size_t len) | ||
26 | { | ||
27 | char szkey1[] = "34d1"; | ||
28 | size_t cchkey1 = strlen(szkey1); | ||
29 | char szkey2[] = "TbnCboEbn"; | ||
30 | size_t cchkey2 = strlen(szkey2); | ||
31 | for (int i = 0; i < static_cast<int>(len); i++) | ||
32 | { | ||
33 | if (len >= cchkey1) | ||
34 | { | ||
35 | if (!strncmp((char*)&buffer[i], szkey1, cchkey1)) | ||
36 | { | ||
37 | return (const char*)&buffer[i]; | ||
38 | } | ||
39 | } | ||
40 | if (len >= cchkey2) | ||
41 | { | ||
42 | if (!strncmp((char*)&buffer[i], szkey2, cchkey2)) | ||
43 | { | ||
44 | return (const char*)&buffer[i]; | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | return NULL; | ||
49 | } | ||
50 | |||
51 | dword zen::find_firmware_offset(byte* buffer, size_t len) | ||
52 | { | ||
53 | for (dword i = 0; i < static_cast<dword>(len); i += 0x10) | ||
54 | { | ||
55 | dword size = *(dword*)&buffer[i]; | ||
56 | if (size < (i + len) && size > (len >> 1)) | ||
57 | { | ||
58 | if (buffer[i + sizeof(dword)] != 0 | ||
59 | && buffer[i + sizeof(dword) + 1] != 0 | ||
60 | && buffer[i + sizeof(dword) + 2] != 0 | ||
61 | && buffer[i + sizeof(dword) + 3] != 0) | ||
62 | { | ||
63 | return i; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | bool zen::find_firmware_archive(const std::string& filename, dword& va, dword& pa) | ||
71 | { | ||
72 | shared::pe_file pef; | ||
73 | if (!pef.read(filename)) | ||
74 | { | ||
75 | return false; | ||
76 | } | ||
77 | shared::section_info data_section; | ||
78 | if (!pef.find_section(".data", data_section)) | ||
79 | { | ||
80 | return false; | ||
81 | } | ||
82 | shared::bytes buffer; | ||
83 | if (!shared::read_file(filename, buffer, data_section.raw_address, | ||
84 | data_section.raw_size)) | ||
85 | { | ||
86 | return false; | ||
87 | } | ||
88 | dword offset = find_firmware_offset(&buffer[0], buffer.size()); | ||
89 | if (!offset) | ||
90 | { | ||
91 | return false; | ||
92 | } | ||
93 | va = data_section.virtual_address + offset; | ||
94 | pa = data_section.raw_address + offset; | ||
95 | |||
96 | return true; | ||
97 | } | ||
98 | |||
99 | |||
100 | bool zen::crypt_firmware(const char* key, byte* buffer, size_t len) | ||
101 | { | ||
102 | // Determine if the key length is dword aligned. | ||
103 | int keylen = strlen(key); | ||
104 | int keylen_rem = keylen % sizeof(dword); | ||
105 | |||
106 | // Determine how many times the key must be repeated to be dword aligned. | ||
107 | int keycycle = keylen_rem ? (sizeof(dword) / keylen_rem) : 1; | ||
108 | int keyscount = (keylen * keycycle) / sizeof(dword); | ||
109 | |||
110 | // Allocate a buffer to hold the key as an array of dwords. | ||
111 | dword* keys = new dword[keyscount]; | ||
112 | |||
113 | // Copy the key into the key array, whilst mutating it. | ||
114 | for (int i = 0; i < keyscount; i++) | ||
115 | { | ||
116 | dword val; | ||
117 | int keyoffset = (i * sizeof(dword)) % keylen; | ||
118 | if ((keyoffset+sizeof(dword)) < keylen) | ||
119 | { | ||
120 | val = *(dword*)&key[keyoffset]; | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | val = key[keyoffset] | ||
125 | | (key[(keyoffset + 1) % keylen] << 8) | ||
126 | | (key[(keyoffset + 2) % keylen] << 16) | ||
127 | | (key[(keyoffset + 3) % keylen] << 24); | ||
128 | } | ||
129 | keys[i] = (val - 0x01010101) | 0x80808080; | ||
130 | } | ||
131 | |||
132 | // Determine the number of dwords in the buffer. | ||
133 | int len_div = len / sizeof(dword); | ||
134 | |||
135 | // Decrypt all dwords of the buffer. | ||
136 | for (int i = 0; i < len_div; i++) | ||
137 | { | ||
138 | ((dword*)buffer)[i] ^= keys[i % keyscount]; | ||
139 | } | ||
140 | |||
141 | // Determine the remaining number of bytes in the buffer. | ||
142 | int len_rem = len % sizeof(dword); | ||
143 | |||
144 | // Decrypt the remaining number of bytes in the buffer. | ||
145 | for (int i = len_div * sizeof(dword); i < len; i++) | ||
146 | { | ||
147 | buffer[i] ^= ((key[i % keylen] - 0x01) | 0x80); | ||
148 | } | ||
149 | |||
150 | return true; | ||
151 | } | ||
diff --git a/utils/zenutils/source/shared/updater.h b/utils/zenutils/source/shared/updater.h new file mode 100755 index 0000000000..57f9979c30 --- /dev/null +++ b/utils/zenutils/source/shared/updater.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef ZEN_UPDATER_H_INCLUDED | ||
20 | #define ZEN_UPDATER_H_INCLUDED | ||
21 | |||
22 | #include <pelib/PeLib.h> | ||
23 | #include <utils.h> | ||
24 | |||
25 | namespace zen { | ||
26 | const char* find_firmware_key(const byte* buffer, size_t len); | ||
27 | dword find_firmware_offset(byte* buffer, size_t len); | ||
28 | bool find_firmware_archive(const std::string& filename, dword& va, dword& pa); | ||
29 | bool crypt_firmware(const char* key, byte* buffer, size_t len); | ||
30 | }; //namespace zen | ||
31 | |||
32 | #endif //ZEN_UPDATER_H_INCLUDED | ||
diff --git a/utils/zenutils/source/shared/utils.cpp b/utils/zenutils/source/shared/utils.cpp new file mode 100755 index 0000000000..8f45de5d3f --- /dev/null +++ b/utils/zenutils/source/shared/utils.cpp | |||
@@ -0,0 +1,211 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include "utils.h" | ||
20 | #include <fstream> | ||
21 | #include <zlib/zlib.h> | ||
22 | |||
23 | |||
24 | std::string shared::replace_extension(const std::string& filename, const std::string& extension) | ||
25 | { | ||
26 | std::string newname; | ||
27 | const char* name = filename.c_str(); | ||
28 | const char* ext = strrchr(name, '.'); | ||
29 | if (ext) | ||
30 | { | ||
31 | // If an extension was found, replace it. | ||
32 | newname.assign(name, ext-name); | ||
33 | newname += extension; | ||
34 | } | ||
35 | else | ||
36 | { | ||
37 | // If an extension was not found, append it. | ||
38 | newname = name; | ||
39 | newname += extension; | ||
40 | } | ||
41 | return newname; | ||
42 | } | ||
43 | |||
44 | std::string shared::remove_extension(const std::string& filename) | ||
45 | { | ||
46 | std::string newname; | ||
47 | const char* name = filename.c_str(); | ||
48 | const char* ext = strrchr(name, '.'); | ||
49 | if (ext) | ||
50 | { | ||
51 | newname.assign(name, ext-name); | ||
52 | } | ||
53 | else | ||
54 | { | ||
55 | newname = name; | ||
56 | } | ||
57 | return newname; | ||
58 | } | ||
59 | |||
60 | std::string shared::double_quote(const std::string& str) | ||
61 | { | ||
62 | std::string out; | ||
63 | for (int i = 0, j = str.length(); i < j; i++) | ||
64 | { | ||
65 | if (str[i] == '\\') | ||
66 | out += "\\\\"; | ||
67 | else | ||
68 | out += str[i]; | ||
69 | } | ||
70 | return out; | ||
71 | } | ||
72 | |||
73 | bool shared::inflate_to_file(const bytes& buffer, const char* filename) | ||
74 | { | ||
75 | // Open output file. | ||
76 | std::ofstream ofs; | ||
77 | ofs.open(filename, std::ios::binary); | ||
78 | if (!ofs) | ||
79 | { | ||
80 | return false; | ||
81 | } | ||
82 | |||
83 | // Initialize zlib. | ||
84 | z_stream d_stream; // decompression stream | ||
85 | |||
86 | d_stream.zalloc = Z_NULL; | ||
87 | d_stream.zfree = Z_NULL; | ||
88 | d_stream.opaque = Z_NULL; | ||
89 | |||
90 | d_stream.next_in = const_cast<bytes::value_type*>(&buffer[0]); | ||
91 | d_stream.avail_in = static_cast<uInt>(buffer.size()); | ||
92 | |||
93 | int ret = inflateInit(&d_stream); | ||
94 | if (ret != Z_OK) | ||
95 | return false; | ||
96 | |||
97 | // Allocate buffer to hold the inflated data. | ||
98 | const size_t BUFSIZE = 1048576; | ||
99 | Bytef* infbuf = new Bytef[BUFSIZE]; | ||
100 | if (!infbuf) | ||
101 | return false; | ||
102 | |||
103 | // Decompress untill the end of the input buffer. | ||
104 | uLong totalout = 0; | ||
105 | bool bLoop = true; | ||
106 | while (bLoop) | ||
107 | { | ||
108 | d_stream.next_out = infbuf; | ||
109 | d_stream.avail_out = BUFSIZE; | ||
110 | |||
111 | ret = inflate(&d_stream, Z_NO_FLUSH); | ||
112 | if (ret == Z_STREAM_END) | ||
113 | { | ||
114 | bLoop = false; | ||
115 | } | ||
116 | else if (ret != Z_OK) | ||
117 | { | ||
118 | inflateEnd(&d_stream); | ||
119 | delete [] infbuf; | ||
120 | return false; | ||
121 | } | ||
122 | |||
123 | // Write the inflated data to the output file. | ||
124 | if (!ofs.write((const char*)infbuf, d_stream.total_out-totalout)) | ||
125 | { | ||
126 | inflateEnd(&d_stream); | ||
127 | delete [] infbuf; | ||
128 | return false; | ||
129 | } | ||
130 | totalout = d_stream.total_out; | ||
131 | } | ||
132 | |||
133 | // Cleanup and return. | ||
134 | inflateEnd(&d_stream); | ||
135 | delete [] infbuf; | ||
136 | |||
137 | return true; | ||
138 | } | ||
139 | |||
140 | bool shared::deflate_to_file(const bytes& buffer, const char* filename) | ||
141 | { | ||
142 | // Open output file. | ||
143 | std::ofstream ofs; | ||
144 | ofs.open(filename, std::ios::binary); | ||
145 | if (!ofs) | ||
146 | { | ||
147 | return false; | ||
148 | } | ||
149 | |||
150 | // Initialize zlib. | ||
151 | z_stream c_stream; // compression stream. | ||
152 | |||
153 | c_stream.zalloc = Z_NULL; | ||
154 | c_stream.zfree = Z_NULL; | ||
155 | c_stream.opaque = Z_NULL; | ||
156 | |||
157 | int ret = deflateInit(&c_stream, Z_BEST_COMPRESSION); | ||
158 | if (ret != Z_OK) | ||
159 | return false; | ||
160 | |||
161 | // Allocate buffer to hold the deflated data. | ||
162 | const size_t BUFSIZE = 1048576; | ||
163 | Bytef* defbuf = new Bytef[BUFSIZE]; | ||
164 | if (!defbuf) | ||
165 | return false; | ||
166 | |||
167 | c_stream.avail_in = static_cast<uInt>(buffer.size()); | ||
168 | c_stream.next_in = const_cast<bytes::value_type*>(&buffer[0]); | ||
169 | |||
170 | // Compress until end of the buffer. | ||
171 | uLong totalout = 0; | ||
172 | bool bLoop = true; | ||
173 | while (bLoop) | ||
174 | { | ||
175 | c_stream.avail_out = BUFSIZE; | ||
176 | c_stream.next_out = defbuf; | ||
177 | |||
178 | ret = deflate(&c_stream, Z_NO_FLUSH); // no bad return value | ||
179 | if (ret == Z_STREAM_END) | ||
180 | { | ||
181 | bLoop = false; | ||
182 | } | ||
183 | else if (ret == Z_BUF_ERROR && !c_stream.avail_in) | ||
184 | { | ||
185 | ret = deflate(&c_stream, Z_FINISH); // no bad return value | ||
186 | bLoop = false; | ||
187 | } | ||
188 | else if (ret != Z_OK) | ||
189 | { | ||
190 | deflateEnd(&c_stream); | ||
191 | delete [] defbuf; | ||
192 | return false; | ||
193 | } | ||
194 | |||
195 | // Write the inflated data to the output file. | ||
196 | if (!ofs.write((const char*)defbuf, c_stream.total_out-totalout)) | ||
197 | { | ||
198 | deflateEnd(&c_stream); | ||
199 | delete [] defbuf; | ||
200 | return false; | ||
201 | } | ||
202 | |||
203 | totalout = c_stream.total_out; | ||
204 | } | ||
205 | |||
206 | // Clean up and return. | ||
207 | deflateEnd(&c_stream); | ||
208 | delete [] defbuf; | ||
209 | |||
210 | return true; | ||
211 | } | ||
diff --git a/utils/zenutils/source/shared/utils.h b/utils/zenutils/source/shared/utils.h new file mode 100755 index 0000000000..ca9e291514 --- /dev/null +++ b/utils/zenutils/source/shared/utils.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef SHARED_UTILS_H_INCLUDED | ||
20 | #define SHARED_UTILS_H_INCLUDED | ||
21 | |||
22 | #include <vector> | ||
23 | #include <pelib/PeLib.h> | ||
24 | |||
25 | #ifndef byte | ||
26 | typedef PeLib::byte byte; | ||
27 | #endif | ||
28 | #ifndef word | ||
29 | typedef PeLib::word word; | ||
30 | #endif | ||
31 | #ifndef dword | ||
32 | typedef PeLib::dword dword; | ||
33 | #endif | ||
34 | |||
35 | namespace shared { | ||
36 | typedef std::vector<byte> bytes; | ||
37 | |||
38 | inline dword swap(dword val) | ||
39 | { | ||
40 | return ((val & 0xFF) << 24) | ||
41 | | ((val & 0xFF00) << 8) | ||
42 | | ((val & 0xFF0000) >> 8) | ||
43 | | ((val & 0xFF000000) >> 24); | ||
44 | } | ||
45 | |||
46 | template <typename _Type> | ||
47 | inline void reverse(_Type* start, _Type* end) | ||
48 | { | ||
49 | while (start < end) | ||
50 | { | ||
51 | *start ^= *end; | ||
52 | *end ^= *start; | ||
53 | *start ^= *end; | ||
54 | start++; | ||
55 | end--; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | std::string replace_extension(const std::string& filename, const std::string& extension); | ||
60 | std::string remove_extension(const std::string& filename); | ||
61 | std::string get_path(const std::string& filename); | ||
62 | std::string double_quote(const std::string& str); | ||
63 | |||
64 | bool inflate_to_file(const bytes& buffer, const char* filename); | ||
65 | bool deflate_to_file(const bytes& buffer, const char* filename); | ||
66 | }; //namespace shared | ||
67 | |||
68 | #endif //SHARED_UTILS_H_INCLUDED | ||
diff --git a/utils/zenutils/source/update_extract/CMakeLists.txt b/utils/zenutils/source/update_extract/CMakeLists.txt new file mode 100755 index 0000000000..813e389bed --- /dev/null +++ b/utils/zenutils/source/update_extract/CMakeLists.txt | |||
@@ -0,0 +1,3 @@ | |||
1 | ADD_EXECUTABLE(update_extract main.cpp) | ||
2 | |||
3 | TARGET_LINK_LIBRARIES (update_extract shared) | ||
diff --git a/utils/zenutils/source/update_extract/main.cpp b/utils/zenutils/source/update_extract/main.cpp new file mode 100755 index 0000000000..0fae29e00c --- /dev/null +++ b/utils/zenutils/source/update_extract/main.cpp | |||
@@ -0,0 +1,279 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <iostream> | ||
20 | #include <iomanip> | ||
21 | #include <ctime> | ||
22 | #include <getpot/getpot.hpp> | ||
23 | #include <file.h> | ||
24 | #include <updater.h> | ||
25 | #include <utils.h> | ||
26 | |||
27 | |||
28 | static const char VERSION[] = "0.1"; | ||
29 | |||
30 | void print_version() | ||
31 | { | ||
32 | std::cout | ||
33 | << "update_extract - Extracts a Creative firmware from an updater" | ||
34 | " executable." << std::endl | ||
35 | << "Version " << VERSION << std::endl | ||
36 | << "Copyright (c) 2007 Rasmus Ry" << std::endl; | ||
37 | } | ||
38 | |||
39 | void print_help() | ||
40 | { | ||
41 | print_version(); | ||
42 | std::cout << std::endl | ||
43 | << "Usage: update_extract [command] [options]" << std::endl | ||
44 | << std::endl | ||
45 | << " Commands:" << std::endl | ||
46 | << " -h,--help" << std::endl | ||
47 | << " prints this message." << std::endl | ||
48 | << " -u,--updater [file]" << std::endl | ||
49 | << " specifies the updater executable." << std::endl | ||
50 | << std::endl | ||
51 | << " Options:" << std::endl | ||
52 | << " -V,--verbose" << std::endl | ||
53 | << " prints verbose messages." << std::endl | ||
54 | << " -f,--firmware [file]" << std::endl | ||
55 | << " specifies the firmware arhive file name." << std::endl | ||
56 | << " -k,--key [key]" << std::endl | ||
57 | << " specifies the firmware archive key." << std::endl | ||
58 | << " -o,--offset [offset]" << std::endl | ||
59 | << " specifies the firmware archive offset in c-style" | ||
60 | " hexadecimal." << std::endl | ||
61 | << std::endl | ||
62 | ; | ||
63 | } | ||
64 | |||
65 | std::string options_name(const std::string& name) | ||
66 | { | ||
67 | return shared::replace_extension(name, ".opt"); | ||
68 | } | ||
69 | |||
70 | std::string default_firmware_name(const std::string& name) | ||
71 | { | ||
72 | return shared::replace_extension(name, "_rk.bin"); | ||
73 | } | ||
74 | |||
75 | int process_arguments(int argc, char* argv[]) | ||
76 | { | ||
77 | //-------------------------------------------------------------------- | ||
78 | // Parse input variables. | ||
79 | //-------------------------------------------------------------------- | ||
80 | |||
81 | GetPot cl(argc, argv); | ||
82 | if (cl.size() == 1 || cl.search(2, "-h", "--help")) | ||
83 | { | ||
84 | print_help(); | ||
85 | return 1; | ||
86 | } | ||
87 | |||
88 | std::string updatername; | ||
89 | if (cl.search("-u") || cl.search("--updater")) | ||
90 | updatername = cl.next(""); | ||
91 | if (updatername.empty()) | ||
92 | { | ||
93 | std::cerr << "Updater executable must be specified." << std::endl; | ||
94 | return 2; | ||
95 | } | ||
96 | |||
97 | std::string firmarename = default_firmware_name(updatername); | ||
98 | if (cl.search("-f") || cl.search("--firmware")) | ||
99 | firmarename = cl.next(firmarename.c_str()); | ||
100 | |||
101 | bool verbose = false; | ||
102 | if (cl.search("-V") || cl.search("--verbose")) | ||
103 | verbose = true; | ||
104 | |||
105 | // Get or find the firmware archive key. | ||
106 | std::string key; | ||
107 | if (cl.search("-k") || cl.search("--key")) | ||
108 | key = cl.next(""); | ||
109 | |||
110 | if (key.empty()) | ||
111 | { | ||
112 | if (verbose) | ||
113 | std::cout << "[*] Looking for firmware archive key..." | ||
114 | << std::endl; | ||
115 | shared::bytes buffer; | ||
116 | if (!shared::read_file(updatername, buffer)) | ||
117 | { | ||
118 | std::cerr << "Failed to read the firmware updater executable." | ||
119 | << std::endl; | ||
120 | return 3; | ||
121 | } | ||
122 | key = zen::find_firmware_key(&buffer[0], buffer.size()); | ||
123 | if (key.empty()) | ||
124 | { | ||
125 | std::cerr << "Failed to find the firmware archive key." | ||
126 | << std::endl; | ||
127 | return 4; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | // Get or find the firmware archive offset. | ||
132 | std::string offset; | ||
133 | dword offset_pa = 0; | ||
134 | if (cl.search("-o") || cl.search("--ofset")) | ||
135 | offset = cl.next(""); | ||
136 | |||
137 | if (offset.empty()) | ||
138 | { | ||
139 | if (verbose) | ||
140 | std::cout << "[*] Looking for firmware archive offset..." | ||
141 | << std::endl; | ||
142 | |||
143 | dword offset_va = 0; | ||
144 | if (!zen::find_firmware_archive(updatername, offset_va, offset_pa)) | ||
145 | { | ||
146 | std::cerr << "Failed to find the firmware archive offset." | ||
147 | << std::endl; | ||
148 | return 5; | ||
149 | } | ||
150 | } | ||
151 | else | ||
152 | { | ||
153 | int offset_val; | ||
154 | if (!sscanf(offset.c_str(), "0x%x", &offset_val)) | ||
155 | { | ||
156 | if (!sscanf(offset.c_str(), "0x%X", &offset_val)) | ||
157 | { | ||
158 | std::cerr << "\'" << offset | ||
159 | << "\' is not a valid c-style hexadecimal value." | ||
160 | << std::endl; | ||
161 | return 6; | ||
162 | } | ||
163 | } | ||
164 | offset_pa = static_cast<dword>(offset_val); | ||
165 | } | ||
166 | |||
167 | // Read firmware archive size. | ||
168 | shared::bytes buffer; | ||
169 | if (!shared::read_file(updatername, buffer, offset_pa, sizeof(dword))) | ||
170 | { | ||
171 | std::cerr << "Failed to read the firmware archive size." << std::endl; | ||
172 | return 7; | ||
173 | } | ||
174 | dword archive_size = *(dword*)&buffer[0]; | ||
175 | |||
176 | if (verbose) | ||
177 | { | ||
178 | std::cout << "[*] Printing input variables..." << std::endl; | ||
179 | std::cout << " Updater executable: " << updatername << std::endl; | ||
180 | std::cout << " Firmware archive: " << firmarename << std::endl; | ||
181 | std::cout << " Key: " << key << std::endl; | ||
182 | std::cout << " Offset: " | ||
183 | << std::hex << std::showbase << std::setw(10) | ||
184 | << std::setfill('0') << std::internal | ||
185 | << offset_pa << std::endl; | ||
186 | std::cout << " Size: " | ||
187 | << std::hex << std::showbase << std::setw(10) | ||
188 | << std::setfill('0') << std::internal | ||
189 | << archive_size << std::endl; | ||
190 | } | ||
191 | |||
192 | |||
193 | //-------------------------------------------------------------------- | ||
194 | // Extract the firmware archive from the updater. | ||
195 | //-------------------------------------------------------------------- | ||
196 | |||
197 | if (verbose) | ||
198 | std::cout << "[*] Reading firmware archive..." << std::endl; | ||
199 | |||
200 | // Read the firmware archive. | ||
201 | offset_pa += sizeof(dword); | ||
202 | if (!shared::read_file(updatername, buffer, offset_pa, archive_size)) | ||
203 | { | ||
204 | std::cerr << "Failed to read the firmware archive." << std::endl; | ||
205 | return 8; | ||
206 | } | ||
207 | |||
208 | if (verbose) | ||
209 | std::cout << "[*] Decrypting firmware archive..." << std::endl; | ||
210 | |||
211 | // Decrypt the firmware archive. | ||
212 | if (!zen::crypt_firmware(key.c_str(), &buffer[0], buffer.size())) | ||
213 | { | ||
214 | std::cerr << "Failed to decrypt the firmware archive." << std::endl; | ||
215 | return 9; | ||
216 | } | ||
217 | |||
218 | if (verbose) | ||
219 | std::cout << "[*] Decompressing firmware archive..." << std::endl; | ||
220 | |||
221 | // Inflate the firmware archive to the output file. | ||
222 | if (!shared::inflate_to_file(buffer, firmarename.c_str())) | ||
223 | { | ||
224 | std::cerr << "Failed to decompress the firmware archive." << std::endl; | ||
225 | return 10; | ||
226 | } | ||
227 | |||
228 | |||
229 | //-------------------------------------------------------------------- | ||
230 | // Generate an options file for the extracted firmware archive. | ||
231 | //-------------------------------------------------------------------- | ||
232 | |||
233 | // Get options filename for the given input file. | ||
234 | std::string optionsname = options_name(updatername); | ||
235 | |||
236 | if (verbose) | ||
237 | std::cout << "[*] Producing options file..." << std::endl; | ||
238 | |||
239 | // Produce options file for the given input file. | ||
240 | std::ofstream ofs; | ||
241 | ofs.open(optionsname.c_str(), std::ios::binary); | ||
242 | if (!ofs) | ||
243 | { | ||
244 | std::cerr << "Failed to create firmware archive options file." | ||
245 | << std::endl; | ||
246 | return 11; | ||
247 | } | ||
248 | |||
249 | time_t timeval = time(NULL); | ||
250 | ofs << "# Options file generated at: " << ctime(&timeval) | ||
251 | << "updater = \'" << shared::double_quote(updatername) << "\'" | ||
252 | << std::endl | ||
253 | << "firmware = \'" << shared::double_quote(firmarename) << "\'" | ||
254 | << std::endl | ||
255 | << "offset = " << (offset_pa - sizeof(dword)) << std::endl | ||
256 | << "size = " << archive_size << std::endl | ||
257 | << "key = \'" << key << "\'" << std::endl; | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | int main(int argc, char* argv[]) | ||
263 | { | ||
264 | try | ||
265 | { | ||
266 | return process_arguments(argc, argv); | ||
267 | } | ||
268 | catch (const std::exception& xcpt) | ||
269 | { | ||
270 | std::cerr << "Exception caught: " << xcpt.what() << std::endl; | ||
271 | return -1; | ||
272 | } | ||
273 | catch (...) | ||
274 | { | ||
275 | std::cerr << "Unknown exception caught." << std::endl; | ||
276 | return -2; | ||
277 | } | ||
278 | return -3; | ||
279 | } | ||
diff --git a/utils/zenutils/source/update_patch/CMakeLists.txt b/utils/zenutils/source/update_patch/CMakeLists.txt new file mode 100755 index 0000000000..11474b7ff8 --- /dev/null +++ b/utils/zenutils/source/update_patch/CMakeLists.txt | |||
@@ -0,0 +1,3 @@ | |||
1 | ADD_EXECUTABLE(update_patch main.cpp) | ||
2 | |||
3 | TARGET_LINK_LIBRARIES (update_patch shared) | ||
diff --git a/utils/zenutils/source/update_patch/main.cpp b/utils/zenutils/source/update_patch/main.cpp new file mode 100755 index 0000000000..d48797b46d --- /dev/null +++ b/utils/zenutils/source/update_patch/main.cpp | |||
@@ -0,0 +1,409 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <iostream> | ||
20 | #include <iomanip> | ||
21 | #include <cstdio> | ||
22 | #include <getpot/getpot.hpp> | ||
23 | #include <file.h> | ||
24 | #include <updater.h> | ||
25 | #include <utils.h> | ||
26 | #include <pe.h> | ||
27 | |||
28 | |||
29 | static const char VERSION[] = "0.1"; | ||
30 | |||
31 | void print_version() | ||
32 | { | ||
33 | std::cout | ||
34 | << "update_patch - Patches a Creative firmware into an updater" | ||
35 | " executable." << std::endl | ||
36 | << "Version " << VERSION << std::endl | ||
37 | << "Copyright (c) 2007 Rasmus Ry" << std::endl; | ||
38 | } | ||
39 | |||
40 | void print_help() | ||
41 | { | ||
42 | print_version(); | ||
43 | std::cout << std::endl | ||
44 | << "Usage: update_patch [command] [options]" << std::endl | ||
45 | << std::endl | ||
46 | << " Commands:" << std::endl | ||
47 | << " -h,--help" << std::endl | ||
48 | << " prints this message." << std::endl | ||
49 | << " -u,--updater [file]" << std::endl | ||
50 | << " specifies the updater executable." << std::endl | ||
51 | << std::endl | ||
52 | << " Options:" << std::endl | ||
53 | << " -V,--verbose" << std::endl | ||
54 | << " prints verbose messages." << std::endl | ||
55 | << " -f,--firmware [file]" << std::endl | ||
56 | << " specifies the firmware arhive file name." << std::endl | ||
57 | << " -k,--key [key]" << std::endl | ||
58 | << " specifies the firmware archive key." << std::endl | ||
59 | << " -o,--offset [offset]" << std::endl | ||
60 | << " specifies the firmware archive offset in c-style" | ||
61 | " hexadecimal." << std::endl | ||
62 | << std::endl | ||
63 | ; | ||
64 | } | ||
65 | |||
66 | std::string options_name(const std::string& name) | ||
67 | { | ||
68 | return shared::replace_extension(name, ".opt"); | ||
69 | } | ||
70 | |||
71 | std::string default_firmware_name(const std::string& name) | ||
72 | { | ||
73 | return shared::replace_extension(name, "_rk.bin"); | ||
74 | } | ||
75 | |||
76 | int process_arguments(int argc, char* argv[]) | ||
77 | { | ||
78 | //-------------------------------------------------------------------- | ||
79 | // Parse input variables. | ||
80 | //-------------------------------------------------------------------- | ||
81 | |||
82 | GetPot cl(argc, argv); | ||
83 | if (cl.size() == 1 || cl.search(2, "-h", "--help")) | ||
84 | { | ||
85 | print_help(); | ||
86 | return 1; | ||
87 | } | ||
88 | |||
89 | std::string updatername; | ||
90 | if (cl.search("-u") || cl.search("--updater")) | ||
91 | updatername = cl.next(""); | ||
92 | if (updatername.empty()) | ||
93 | { | ||
94 | std::cerr << "Updater executable must be specified." << std::endl; | ||
95 | return 2; | ||
96 | } | ||
97 | |||
98 | bool verbose = false; | ||
99 | if (cl.search("-V") || cl.search("--verbose")) | ||
100 | verbose = true; | ||
101 | |||
102 | if (verbose) | ||
103 | std::cout << "[*] Parsing options file..." << std::endl; | ||
104 | |||
105 | GetPot optfile(options_name(updatername.c_str()).c_str()); | ||
106 | if (verbose) | ||
107 | optfile.print(); | ||
108 | |||
109 | std::string firmwarename = optfile("firmware", | ||
110 | default_firmware_name(updatername).c_str()); | ||
111 | dword offset_pa = optfile("offset", 0); | ||
112 | dword size = optfile("size", 0); | ||
113 | std::string key = optfile("key", ""); | ||
114 | |||
115 | if (cl.search("-f") || cl.search("--firmware")) | ||
116 | firmwarename = cl.next(firmwarename.c_str()); | ||
117 | |||
118 | std::string offset; | ||
119 | if (cl.search("-o") || cl.search("--offset")) | ||
120 | offset = cl.next(""); | ||
121 | |||
122 | if (offset.empty() && !offset_pa) | ||
123 | { | ||
124 | if (verbose) | ||
125 | std::cout << "[*] Looking for firmware archive offset..." | ||
126 | << std::endl; | ||
127 | |||
128 | dword offset_va = 0; | ||
129 | if (!zen::find_firmware_archive(updatername, offset_va, offset_pa)) | ||
130 | { | ||
131 | std::cerr << "Failed to find the firmware archive offset." | ||
132 | << std::endl; | ||
133 | return 3; | ||
134 | } | ||
135 | } | ||
136 | else if (!offset_pa) | ||
137 | { | ||
138 | int offset_val; | ||
139 | if (!sscanf(offset.c_str(), "0x%x", &offset_val)) | ||
140 | { | ||
141 | if (!sscanf(offset.c_str(), "0x%X", &offset_val)) | ||
142 | { | ||
143 | std::cerr << "\'" << offset | ||
144 | << "\' is not a valid c-style hexadecimal value." | ||
145 | << std::endl; | ||
146 | return 4; | ||
147 | } | ||
148 | } | ||
149 | offset_pa = static_cast<dword>(offset_val); | ||
150 | } | ||
151 | |||
152 | if (key.empty()) | ||
153 | { | ||
154 | if (verbose) | ||
155 | std::cout << "[*] Looking for firmware archive key..." | ||
156 | << std::endl; | ||
157 | shared::bytes buffer; | ||
158 | if (!shared::read_file(updatername, buffer)) | ||
159 | { | ||
160 | std::cerr << "Failed to read the firmware updater executable." | ||
161 | << std::endl; | ||
162 | return 5; | ||
163 | } | ||
164 | key = zen::find_firmware_key(&buffer[0], buffer.size()); | ||
165 | if (key.empty()) | ||
166 | { | ||
167 | std::cerr << "Failed to find the firmware archive key." | ||
168 | << std::endl; | ||
169 | return 6; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | if (verbose) | ||
174 | { | ||
175 | std::cout << "[*] Printing input variables..." << std::endl; | ||
176 | std::cout << " Updater executable: " << updatername << std::endl; | ||
177 | std::cout << " Firmware archive: " << firmwarename << std::endl; | ||
178 | std::cout << " Key: " << key << std::endl; | ||
179 | std::cout << " Offset: " | ||
180 | << std::hex << std::showbase << std::setw(10) | ||
181 | << std::setfill('0') << std::internal | ||
182 | << offset_pa << std::endl; | ||
183 | std::cout << " Size: " | ||
184 | << std::hex << std::showbase << std::setw(10) | ||
185 | << std::setfill('0') << std::internal | ||
186 | << size << std::endl; | ||
187 | } | ||
188 | |||
189 | |||
190 | //-------------------------------------------------------------------- | ||
191 | // Prepare the firmware archive for being patched into the updater. | ||
192 | //-------------------------------------------------------------------- | ||
193 | |||
194 | if (verbose) | ||
195 | std::cout << "[*] Reading firmware archive..." << std::endl; | ||
196 | |||
197 | shared::bytes buffer; | ||
198 | if (!shared::read_file(firmwarename, buffer)) | ||
199 | { | ||
200 | std::cerr << "Failed to read the firmware archive." << std::endl; | ||
201 | return 7; | ||
202 | } | ||
203 | |||
204 | if (verbose) | ||
205 | std::cout << " Bytes read: " | ||
206 | << std::hex << std::showbase << std::setw(10) | ||
207 | << std::setfill('0') << std::internal | ||
208 | << buffer.size() << std::endl; | ||
209 | |||
210 | if (verbose) | ||
211 | std::cout << "[*] Compressing firmware archive..." << std::endl; | ||
212 | |||
213 | std::string compfirmware = shared::replace_extension(firmwarename, ".def"); | ||
214 | if (!shared::deflate_to_file(buffer, compfirmware.c_str())) | ||
215 | { | ||
216 | std::cerr << "Failed to compress the firmware archive." << std::endl; | ||
217 | return 8; | ||
218 | } | ||
219 | |||
220 | if (verbose) | ||
221 | std::cout << "[*] Reading compressed firmware archive..." << std::endl; | ||
222 | |||
223 | if (!shared::read_file(compfirmware, buffer)) | ||
224 | { | ||
225 | std::cerr << "Failed to read the compressed firmware archive." | ||
226 | << std::endl; | ||
227 | return 9; | ||
228 | } | ||
229 | |||
230 | if (verbose) | ||
231 | std::cout << " Bytes read: " | ||
232 | << std::hex << std::showbase << std::setw(10) | ||
233 | << std::setfill('0') << std::internal | ||
234 | << buffer.size() << std::endl; | ||
235 | |||
236 | // Delete the temporary firmware file. | ||
237 | std::remove(compfirmware.c_str()); | ||
238 | |||
239 | if (verbose) | ||
240 | std::cout << "[*] Encrypting compressed firmware archive..." | ||
241 | << std::endl; | ||
242 | |||
243 | if (!zen::crypt_firmware(key.c_str(), &buffer[0], buffer.size())) | ||
244 | { | ||
245 | std::cerr << "Failed to encrypt the compressed firmware archive." | ||
246 | << std::endl; | ||
247 | return 10; | ||
248 | } | ||
249 | |||
250 | |||
251 | //-------------------------------------------------------------------- | ||
252 | // Backup the updater and patch the firmware archive into it. | ||
253 | //-------------------------------------------------------------------- | ||
254 | |||
255 | if (verbose) | ||
256 | std::cout << "[*] Backing up the updater executable..." << std::endl; | ||
257 | |||
258 | if (!shared::backup_file(updatername)) | ||
259 | { | ||
260 | std::cerr << "Failed to backup the updater executable." << std::endl; | ||
261 | return 11; | ||
262 | } | ||
263 | |||
264 | // Is there enough space within the existing firmware archive | ||
265 | // to hold the new one? | ||
266 | if (size < buffer.size()) | ||
267 | { | ||
268 | // No, we need to add a new section to hold the new firmware archive. | ||
269 | if (verbose) | ||
270 | std::cout << "[*] Adding new section to the updater executable..." | ||
271 | << std::endl; | ||
272 | |||
273 | // Construct a new buffer with the archive size prepended. | ||
274 | shared::bytes newbuffer(buffer.size() + sizeof(dword)); | ||
275 | *(dword*)&newbuffer[0] = static_cast<dword>(buffer.size()); | ||
276 | std::copy(buffer.begin(), buffer.end(), &newbuffer[4]); | ||
277 | |||
278 | // Read the updater portable executable. | ||
279 | shared::pe_file pef; | ||
280 | if (!pef.read(updatername)) | ||
281 | { | ||
282 | std::cerr << "Failed to read the updater portable executable" | ||
283 | " structure." << std::endl; | ||
284 | return 12; | ||
285 | } | ||
286 | |||
287 | // Add a new section to the updater, containing the encrypted | ||
288 | // firmware archive. | ||
289 | shared::section_info newsection; | ||
290 | if (!pef.add_section(".firm", newbuffer, newsection)) | ||
291 | { | ||
292 | std::cerr << "Failed to add an extra section to the updater" | ||
293 | " executable." << std::endl; | ||
294 | return 13; | ||
295 | } | ||
296 | |||
297 | if (verbose) | ||
298 | std::cout << "[*] Relocating code references to the firmware" | ||
299 | " archive..." << std::endl; | ||
300 | |||
301 | // Locate the code section. | ||
302 | shared::section_info textsection; | ||
303 | if (!pef.find_section(".text", textsection)) | ||
304 | { | ||
305 | std::cerr << "Failed to find the code section in the updater" | ||
306 | " executable." << std::endl; | ||
307 | return 14; | ||
308 | } | ||
309 | |||
310 | // Read the code section data. | ||
311 | if (!shared::read_file(updatername, buffer, textsection.raw_address, | ||
312 | textsection.raw_size)) | ||
313 | { | ||
314 | std::cerr << "Failed to read the code section from the updater" | ||
315 | " executable." << std::endl; | ||
316 | return 15; | ||
317 | } | ||
318 | |||
319 | // Determine the addresses of the new and old firmware archives. | ||
320 | dword oldva = pef.pa_to_va(offset_pa); | ||
321 | dword newva = pef.pa_to_va(newsection.raw_address); | ||
322 | if (!oldva || !newva) | ||
323 | { | ||
324 | std::cerr << "Failed to compute address of the new or old" | ||
325 | " archive." << std::endl; | ||
326 | return 16; | ||
327 | } | ||
328 | |||
329 | // Relocate references to the old firmware archive. | ||
330 | dword imgbase = pef.get_image_base(); | ||
331 | for (int i = 0, j = buffer.size() - sizeof(dword) + 1; i < j; i++) | ||
332 | { | ||
333 | dword val = *(dword*)&buffer[i]; | ||
334 | if (val >= oldva && val <= (oldva + 3)) | ||
335 | { | ||
336 | *(dword*)&buffer[i] = newva + (val - oldva); | ||
337 | if (verbose) | ||
338 | std::cout << " " | ||
339 | << std::hex << std::showbase << std::setw(10) | ||
340 | << std::setfill('0') << std::internal | ||
341 | << (imgbase + textsection.virtual_address + i) | ||
342 | << ": " | ||
343 | << std::hex << std::showbase << std::setw(10) | ||
344 | << std::setfill('0') << std::internal | ||
345 | << val | ||
346 | << " -> " | ||
347 | << std::hex << std::showbase << std::setw(10) | ||
348 | << std::setfill('0') << std::internal | ||
349 | << (newva + (val - oldva)) << std::endl; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | // Write the relocated code section data. | ||
354 | if (!shared::write_file(updatername, buffer, false, textsection.raw_address, | ||
355 | buffer.size())) | ||
356 | { | ||
357 | std::cerr << "Failed to write the relocated code section to the" | ||
358 | " updater executable." << std::endl; | ||
359 | return 17; | ||
360 | } | ||
361 | } //if (size < buffer.size()) | ||
362 | else | ||
363 | { | ||
364 | // Yes, overwrite the existing firmware archive. | ||
365 | if (verbose) | ||
366 | std::cout << "[*] Overwriting existing firmware archive..." | ||
367 | << std::endl; | ||
368 | |||
369 | shared::bytes archive_size(sizeof(dword)); | ||
370 | *(dword*)&archive_size[0] = buffer.size(); | ||
371 | |||
372 | if (!shared::write_file(updatername, archive_size, false, offset_pa, | ||
373 | archive_size.size())) | ||
374 | { | ||
375 | std::cerr << "Failed to write archive size to the updater" | ||
376 | " executable." << std::endl; | ||
377 | return 18; | ||
378 | } | ||
379 | |||
380 | if (!shared::write_file(updatername, buffer, false, | ||
381 | offset_pa+archive_size.size(), buffer.size())) | ||
382 | { | ||
383 | std::cerr << "Failed to write the new archive to the updater" | ||
384 | " exectuable." << std::endl; | ||
385 | return 19; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | int main(int argc, char* argv[]) | ||
393 | { | ||
394 | try | ||
395 | { | ||
396 | return process_arguments(argc, argv); | ||
397 | } | ||
398 | catch (const std::exception& xcpt) | ||
399 | { | ||
400 | std::cerr << "Exception caught: " << xcpt.what() << std::endl; | ||
401 | return -1; | ||
402 | } | ||
403 | catch (...) | ||
404 | { | ||
405 | std::cerr << "Unknown exception caught." << std::endl; | ||
406 | return -2; | ||
407 | } | ||
408 | return -3; | ||
409 | } | ||
diff --git a/utils/zenutils/source/zen_crypt/CMakeLists.txt b/utils/zenutils/source/zen_crypt/CMakeLists.txt new file mode 100755 index 0000000000..e88e8951a5 --- /dev/null +++ b/utils/zenutils/source/zen_crypt/CMakeLists.txt | |||
@@ -0,0 +1,4 @@ | |||
1 | ADD_EXECUTABLE(zen_crypt main.cpp) | ||
2 | |||
3 | TARGET_LINK_LIBRARIES(zen_crypt shared) | ||
4 | TARGET_LINK_LIBRARIES(zen_crypt beecrypt) | ||
diff --git a/utils/zenutils/source/zen_crypt/main.cpp b/utils/zenutils/source/zen_crypt/main.cpp new file mode 100755 index 0000000000..8301cbbea5 --- /dev/null +++ b/utils/zenutils/source/zen_crypt/main.cpp | |||
@@ -0,0 +1,687 @@ | |||
1 | /* zenutils - Utilities for working with creative firmwares. | ||
2 | * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <iostream> | ||
20 | #include <getpot/getpot.hpp> | ||
21 | #include <cenc.h> | ||
22 | #include <crypt.h> | ||
23 | #include <file.h> | ||
24 | #include <firmware.h> | ||
25 | #include <utils.h> | ||
26 | |||
27 | |||
28 | namespace { | ||
29 | enum command_t | ||
30 | { | ||
31 | cmd_none = 0, | ||
32 | cmd_sign, | ||
33 | cmd_verify, | ||
34 | cmd_encrypt, | ||
35 | cmd_decrypt | ||
36 | }; | ||
37 | |||
38 | enum mode_t | ||
39 | { | ||
40 | mode_none = 0, | ||
41 | mode_cenc, | ||
42 | mode_fresc, | ||
43 | mode_tl | ||
44 | }; | ||
45 | |||
46 | struct player_info_t | ||
47 | { | ||
48 | const char* name; | ||
49 | const char* null_key; // HMAC-SHA1 key | ||
50 | const char* fresc_key; // BlowFish key | ||
51 | const char* tl_key; // BlowFish key | ||
52 | bool big_endian; | ||
53 | }; | ||
54 | }; //namespace | ||
55 | |||
56 | |||
57 | static const char VERSION[] = "0.1"; | ||
58 | |||
59 | static const char null_key_v1[] = "CTL:N0MAD|PDE0.SIGN."; | ||
60 | static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP."; | ||
61 | |||
62 | static const char fresc_key[] = "Copyright (C) CTL. -" | ||
63 | " zN0MAD iz v~p0wderful!"; | ||
64 | |||
65 | static const char tl_zvm_key[] = "1sN0TM3D az u~may th1nk*" | ||
66 | "Creative Zen Vision:M"; | ||
67 | static const char tl_zvw_key[] = "1sN0TM3D az u~may th1nk*" | ||
68 | "Creative ZEN Vision W"; | ||
69 | static const char tl_zm_key[] = "1sN0TM3D az u~may th1nk*" | ||
70 | "Creative Zen Micro"; | ||
71 | static const char tl_zmp_key[] = "1sN0TM3D az u~may th1nk*" | ||
72 | "Creative Zen MicroPhoto"; | ||
73 | static const char tl_zs_key[] = "1sN0TM3D az u~may th1nk*" | ||
74 | "Creative Zen Sleek"; | ||
75 | static const char tl_zsp_key[] = "1sN0TM3D az u~may th1nk*" | ||
76 | "Creative Zen Sleek Photo"; | ||
77 | static const char tl_zt_key[] = "1sN0TM3D az u~may th1nk*" | ||
78 | "Creative Zen Touch"; | ||
79 | static const char tl_zx_key[] = "1sN0TM3D az u~may th1nk*" | ||
80 | "NOMAD Jukebox Zen Xtra"; | ||
81 | |||
82 | player_info_t players[] = { | ||
83 | {"Vision:M", null_key_v2, fresc_key, tl_zvm_key, false}, | ||
84 | {"Vision W", null_key_v2, fresc_key, tl_zvw_key, false}, | ||
85 | {"Micro", null_key_v1, fresc_key, tl_zm_key, true}, | ||
86 | {"MicroPhoto", null_key_v1, fresc_key, tl_zmp_key, true}, | ||
87 | {"Sleek", null_key_v1, fresc_key, tl_zs_key, true}, | ||
88 | {"SleekPhoto", null_key_v1, fresc_key, tl_zsp_key, true}, | ||
89 | {"Touch", null_key_v1, fresc_key, tl_zt_key, true}, | ||
90 | {"Xtra", null_key_v1, fresc_key, tl_zx_key, true}, | ||
91 | {NULL, NULL, NULL, NULL, false} | ||
92 | }; | ||
93 | |||
94 | |||
95 | player_info_t* find_player_info(std::string player) | ||
96 | { | ||
97 | for (int i = 0; players[i].name != NULL; i++) | ||
98 | { | ||
99 | if (!stricmp(players[i].name, player.c_str())) | ||
100 | { | ||
101 | return &players[i]; | ||
102 | } | ||
103 | } | ||
104 | return NULL; | ||
105 | } | ||
106 | |||
107 | void print_version() | ||
108 | { | ||
109 | std::cout | ||
110 | << "zen_crypt - A utility for encrypting, decrypting or signing" | ||
111 | " Creative firmwares." << std::endl | ||
112 | << "Version " << VERSION << std::endl | ||
113 | << "Copyright (c) 2007 Rasmus Ry" << std::endl; | ||
114 | } | ||
115 | |||
116 | void print_help() | ||
117 | { | ||
118 | print_version(); | ||
119 | std::cout << std::endl | ||
120 | << "Usage: zen_crypt [command] [options]" << std::endl | ||
121 | << std::endl | ||
122 | << " Commands:" << std::endl | ||
123 | << " -h,--help" << std::endl | ||
124 | << " prints this message." << std::endl | ||
125 | << " -s,--sign" << std::endl | ||
126 | << " signs a given input file." << std::endl | ||
127 | << " -v,--verify" << std::endl | ||
128 | << " verifies a signed input file." << std::endl | ||
129 | << " -e,--encrypt" << std::endl | ||
130 | << " encrypts a given input file." << std::endl | ||
131 | << " -d,--decrypt" << std::endl | ||
132 | << " decrypts a given input file." << std::endl | ||
133 | << std::endl | ||
134 | << " Options:" << std::endl | ||
135 | << " -V,--verbose" << std::endl | ||
136 | << " prints verbose messages." << std::endl | ||
137 | << " -b,--big-endian" << std::endl | ||
138 | << " specifies that the input is big-endian, default is" | ||
139 | " little-endian." << std::endl | ||
140 | << " -i,--input [file]" << std::endl | ||
141 | << " specifies the input file." << std::endl | ||
142 | << " -o,--output [file]" << std::endl | ||
143 | << " specifies the output file." << std::endl | ||
144 | << " -m,--mode [CENC|FRESC|TL]" << std::endl | ||
145 | << " specifies which algorithm to use." << std::endl | ||
146 | << " -k,--key [player|key]" << std::endl | ||
147 | << " specifies which key to use." << std::endl | ||
148 | << std::endl | ||
149 | ; | ||
150 | std::cout << " Players:" << std::endl; | ||
151 | for (int i = 0; players[i].name != NULL; i++) | ||
152 | { | ||
153 | std::cout << " " << players[i].name; | ||
154 | if (!i) | ||
155 | std::cout << " (default)"; | ||
156 | std::cout << std::endl; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | size_t find_null_signature(shared::bytes& data) | ||
161 | { | ||
162 | size_t index = data.size(); | ||
163 | if (index < (20 + 8 + 7)) | ||
164 | return 0; | ||
165 | index -= 20 + 8; | ||
166 | for (int i = 0; i < 7; i++) | ||
167 | { | ||
168 | if (*(dword*)&data[index-i] == 'NULL' || | ||
169 | *(dword*)&data[index-i] == 'LLUN') | ||
170 | { | ||
171 | return index-i; | ||
172 | } | ||
173 | } | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | |||
178 | bool sign(shared::bytes& data, player_info_t* pi, const std::string& file, | ||
179 | bool verbose) | ||
180 | { | ||
181 | if (verbose) | ||
182 | std::cout << "[*] Checking for the presence of an existing" | ||
183 | " NULL signature..." << std::endl; | ||
184 | size_t index = find_null_signature(data); | ||
185 | if (index) | ||
186 | { | ||
187 | if (verbose) | ||
188 | std::cout << "[*] Found NULL signature at: " | ||
189 | << std::hex << index << std::endl; | ||
190 | |||
191 | if (verbose) | ||
192 | std::cout << "[*] Computing digest..." << std::endl; | ||
193 | |||
194 | shared::bytes digest(20); | ||
195 | if (!zen::hmac_sha1_calc((const byte*)pi->null_key, | ||
196 | strlen(pi->null_key)+1, &data[0], index, | ||
197 | &digest[0], NULL)) | ||
198 | { | ||
199 | std::cerr << "Failed to compute digest." << std::endl; | ||
200 | return false; | ||
201 | } | ||
202 | |||
203 | if (verbose) | ||
204 | std::cout << "[*] Writing file data..." << std::endl; | ||
205 | |||
206 | if (!shared::write_file(file, data, true)) | ||
207 | { | ||
208 | std::cerr << "Failed to write file data." << std::endl; | ||
209 | return false; | ||
210 | } | ||
211 | |||
212 | if (verbose) | ||
213 | std::cout << "[*] Writing digest data..." << std::endl; | ||
214 | |||
215 | if (!shared::write_file(file, digest, false, index+8)) | ||
216 | { | ||
217 | std::cerr << "Failed to write digest data." << std::endl; | ||
218 | return false; | ||
219 | } | ||
220 | } | ||
221 | else | ||
222 | { | ||
223 | if (verbose) | ||
224 | std::cout << "[*] Computing digest..." << std::endl; | ||
225 | |||
226 | shared::bytes signature(20+8); | ||
227 | if (!zen::hmac_sha1_calc((const byte*)pi->null_key, | ||
228 | strlen(pi->null_key)+1, &data[0], data.size(), | ||
229 | &signature[8], NULL)) | ||
230 | { | ||
231 | std::cerr << "Failed to compute digest." << std::endl; | ||
232 | return false; | ||
233 | } | ||
234 | |||
235 | |||
236 | zen::firmware_header_t header = {'NULL', 20}; | ||
237 | if (pi->big_endian) | ||
238 | { | ||
239 | header.tag = shared::swap(header.tag); | ||
240 | header.size = shared::swap(header.size); | ||
241 | } | ||
242 | memcpy(&signature[0], &header, sizeof(zen::firmware_header_t)); | ||
243 | |||
244 | if (verbose) | ||
245 | std::cout << "[*] Writing file data..." << std::endl; | ||
246 | |||
247 | if (!shared::write_file(file, data, true)) | ||
248 | { | ||
249 | std::cerr << "Failed to write file data." << std::endl; | ||
250 | return false; | ||
251 | } | ||
252 | |||
253 | if (verbose) | ||
254 | std::cout << "[*] Writing signature data..." << std::endl; | ||
255 | |||
256 | if (!shared::write_file(file, signature, false, data.size())) | ||
257 | { | ||
258 | std::cerr << "Failed to write signature data." << std::endl; | ||
259 | return false; | ||
260 | } | ||
261 | |||
262 | if (verbose) | ||
263 | std::cout << "[*] Ensuring that the file length is" | ||
264 | " 32-bit aligned..." << std::endl; | ||
265 | |||
266 | int length = data.size() + signature.size(); | ||
267 | int align = length % 4; | ||
268 | if (align) | ||
269 | { | ||
270 | shared::bytes padding(4 - align, 0); | ||
271 | if (!shared::write_file(file, padding, false, length)) | ||
272 | { | ||
273 | std::cerr << "Failed to write padding data." << std::endl; | ||
274 | return false; | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | return true; | ||
280 | } | ||
281 | |||
282 | bool verify(shared::bytes& data, player_info_t* pi, bool verbose) | ||
283 | { | ||
284 | if (verbose) | ||
285 | std::cout << "[*] Checking for the presence of an existing" | ||
286 | " NULL signature..." << std::endl; | ||
287 | size_t index = find_null_signature(data); | ||
288 | if (!index) | ||
289 | { | ||
290 | std::cerr << "No NULL signature present in the input file." | ||
291 | << std::endl; | ||
292 | return false; | ||
293 | } | ||
294 | if (verbose) | ||
295 | std::cout << "[*] Found NULL signature at: " | ||
296 | << std::hex << index << std::endl; | ||
297 | |||
298 | if (verbose) | ||
299 | std::cout << "[*] Computing digest..." << std::endl; | ||
300 | |||
301 | byte digest[20]; | ||
302 | if (!zen::hmac_sha1_calc((const byte*)pi->null_key, strlen(pi->null_key)+1, | ||
303 | &data[0], index, digest, NULL)) | ||
304 | { | ||
305 | std::cerr << "Failed to compute digest." << std::endl; | ||
306 | return false; | ||
307 | } | ||
308 | |||
309 | if (verbose) | ||
310 | std::cout << "[*] Verifying NULL signature digest..." << std::endl; | ||
311 | |||
312 | if (memcmp(&digest[0], &data[index+8], 20)) | ||
313 | { | ||
314 | std::cerr << "The NULL signature contains an incorrect digest." | ||
315 | << std::endl; | ||
316 | return false; | ||
317 | } | ||
318 | |||
319 | return true; | ||
320 | } | ||
321 | |||
322 | bool encrypt(shared::bytes& data, int mode, player_info_t* pi, | ||
323 | const std::string& file, bool verbose) | ||
324 | { | ||
325 | if (mode == mode_cenc) | ||
326 | { | ||
327 | if (verbose) | ||
328 | std::cout << "[*] Encoding input file..." << std::endl; | ||
329 | |||
330 | shared::bytes outbuf(data.size() * 2); | ||
331 | int len = zen::cenc_encode(&data[0], data.size(), &outbuf[0], outbuf.size()); | ||
332 | if (!len) | ||
333 | { | ||
334 | std::cerr << "Failed to encode the input file." << std::endl; | ||
335 | return false; | ||
336 | } | ||
337 | |||
338 | if (verbose) | ||
339 | std::cout << "[*] Writing decoded length to file..." << std::endl; | ||
340 | |||
341 | shared::bytes length(sizeof(dword)); | ||
342 | *(dword*)&length[0] = pi->big_endian ? shared::swap(data.size()) : data.size(); | ||
343 | if (!shared::write_file(file, length, true)) | ||
344 | { | ||
345 | std::cerr << "Failed to write the file data." << std::endl; | ||
346 | return false; | ||
347 | } | ||
348 | |||
349 | if (verbose) | ||
350 | std::cout << "[*] Writing file data..." << std::endl; | ||
351 | |||
352 | if (!shared::write_file(file, outbuf, sizeof(dword), len)) | ||
353 | { | ||
354 | std::cerr << "Failed to write the file data." << std::endl; | ||
355 | return false; | ||
356 | } | ||
357 | } | ||
358 | else if (mode == mode_fresc) | ||
359 | { | ||
360 | std::cerr << "FRESC mode is not supported." << std::endl; | ||
361 | return false; | ||
362 | } | ||
363 | else if (mode == mode_tl) | ||
364 | { | ||
365 | if (verbose) | ||
366 | std::cout << "[*] Encoding input file..." << std::endl; | ||
367 | |||
368 | shared::bytes outbuf(data.size() * 2); | ||
369 | *(dword*)&outbuf[0] = pi->big_endian ? shared::swap(data.size()) : data.size(); | ||
370 | int len = zen::cenc_encode(&data[0], data.size(), | ||
371 | &outbuf[sizeof(dword)], | ||
372 | outbuf.size()-sizeof(dword)); | ||
373 | if (!len) | ||
374 | { | ||
375 | std::cerr << "Failed to encode the input file." << std::endl; | ||
376 | return false; | ||
377 | } | ||
378 | len += sizeof(dword); | ||
379 | |||
380 | int align = len % 8; | ||
381 | align = align ? (8 - align) : 0; | ||
382 | len += align; | ||
383 | |||
384 | if (verbose) | ||
385 | std::cout << "[*] Encrypting encoded data..." << std::endl; | ||
386 | |||
387 | dword iv[2] = {0, shared::swap(len)}; | ||
388 | if (!zen::bf_cbc_encrypt((const byte*)pi->tl_key, strlen(pi->tl_key)+1, | ||
389 | &outbuf[0], len, (const byte*)iv)) | ||
390 | { | ||
391 | std::cerr << "Failed to decrypt the input file." << std::endl; | ||
392 | return false; | ||
393 | } | ||
394 | |||
395 | if (verbose) | ||
396 | std::cout << "[*] Writing file data..." << std::endl; | ||
397 | |||
398 | if (!shared::write_file(file, outbuf, true, 0, len)) | ||
399 | { | ||
400 | std::cerr << "Failed to save the output file." << std::endl; | ||
401 | return false; | ||
402 | } | ||
403 | } | ||
404 | else | ||
405 | { | ||
406 | std::cerr << "Invalid mode specified." << std::endl; | ||
407 | return false; | ||
408 | } | ||
409 | |||
410 | return true; | ||
411 | } | ||
412 | |||
413 | bool decrypt(shared::bytes& data, int mode, player_info_t* pi, | ||
414 | const std::string& file, bool verbose) | ||
415 | { | ||
416 | if (mode == mode_cenc) | ||
417 | { | ||
418 | dword length = *(dword*)&data[0]; | ||
419 | length = pi->big_endian ? shared::swap(length) : length; | ||
420 | |||
421 | if (verbose) | ||
422 | std::cout << "[*] Decoding input file..." << std::endl; | ||
423 | |||
424 | shared::bytes outbuf(length); | ||
425 | if (!zen::cenc_decode(&data[sizeof(dword)], data.size()-sizeof(dword), | ||
426 | &outbuf[0], length)) | ||
427 | { | ||
428 | std::cerr << "Failed to decode the input file." << std::endl; | ||
429 | return false; | ||
430 | } | ||
431 | |||
432 | if (verbose) | ||
433 | std::cout << "[*] Writing file data..." << std::endl; | ||
434 | |||
435 | if (!shared::write_file(file, outbuf, true)) | ||
436 | { | ||
437 | std::cerr << "Failed to write the file data." << std::endl; | ||
438 | return false; | ||
439 | } | ||
440 | } | ||
441 | else if (mode == mode_fresc) | ||
442 | { | ||
443 | if (verbose) | ||
444 | std::cout << "[*] Decrypting input file..." << std::endl; | ||
445 | |||
446 | dword iv[2] = {shared::swap(data.size()), 0}; | ||
447 | if (!zen::bf_cbc_decrypt((const byte*)pi->fresc_key, | ||
448 | strlen(pi->fresc_key)+1, &data[0], | ||
449 | data.size(), (const byte*)iv)) | ||
450 | { | ||
451 | std::cerr << "Failed to decrypt the input file." << std::endl; | ||
452 | return false; | ||
453 | } | ||
454 | |||
455 | if (verbose) | ||
456 | std::cout << "[*] Writing file data..." << std::endl; | ||
457 | |||
458 | if (!shared::write_file(file, data, true)) | ||
459 | { | ||
460 | std::cerr << "Failed to save the output file." << std::endl; | ||
461 | return false; | ||
462 | } | ||
463 | } | ||
464 | else if (mode == mode_tl) | ||
465 | { | ||
466 | if (verbose) | ||
467 | std::cout << "[*] Decrypting input file..." << std::endl; | ||
468 | |||
469 | dword iv[2] = {0, shared::swap(data.size())}; | ||
470 | if (!zen::bf_cbc_decrypt((const byte*)pi->tl_key, strlen(pi->tl_key)+1, | ||
471 | &data[0], data.size(), (const byte*)iv)) | ||
472 | { | ||
473 | std::cerr << "Failed to decrypt the input file." << std::endl; | ||
474 | return false; | ||
475 | } | ||
476 | |||
477 | dword length = *(dword*)&data[0]; | ||
478 | length = pi->big_endian ? shared::swap(length) : length; | ||
479 | if (length > (data.size() * 3)) | ||
480 | { | ||
481 | std::cerr << "Decrypted length is unexpectedly large: " | ||
482 | << std::hex << length | ||
483 | << " Check the endian and key settings." << std::endl; | ||
484 | return false; | ||
485 | } | ||
486 | |||
487 | if (verbose) | ||
488 | std::cout << "[*] Decoding decrypted data..." << std::endl; | ||
489 | |||
490 | shared::bytes outbuf(length); | ||
491 | if (!zen::cenc_decode(&data[sizeof(dword)], data.size()-sizeof(dword), | ||
492 | &outbuf[0], length)) | ||
493 | { | ||
494 | std::cerr << "Failed to decode the input file." << std::endl; | ||
495 | return false; | ||
496 | } | ||
497 | |||
498 | if (verbose) | ||
499 | std::cout << "[*] Writing file data..." << std::endl; | ||
500 | |||
501 | if (!shared::write_file(file, outbuf, true)) | ||
502 | { | ||
503 | std::cerr << "Failed to save the output file." << std::endl; | ||
504 | return false; | ||
505 | } | ||
506 | } | ||
507 | else | ||
508 | { | ||
509 | std::cerr << "Invalid mode specified." << std::endl; | ||
510 | return false; | ||
511 | } | ||
512 | |||
513 | return true; | ||
514 | } | ||
515 | |||
516 | int process_arguments(int argc, char*argv[]) | ||
517 | { | ||
518 | //-------------------------------------------------------------------- | ||
519 | // Parse input variables. | ||
520 | //-------------------------------------------------------------------- | ||
521 | |||
522 | GetPot cl(argc, argv); | ||
523 | if (cl.size() == 1 || cl.search(2, "-h", "--help")) | ||
524 | { | ||
525 | print_help(); | ||
526 | return 1; | ||
527 | } | ||
528 | |||
529 | int command = cmd_none; | ||
530 | if (cl.search(2, "-s", "--sign")) | ||
531 | command = cmd_sign; | ||
532 | else if (cl.search(2, "-v", "--verify")) | ||
533 | command = cmd_verify; | ||
534 | else if (cl.search(2, "-e", "--encrypt")) | ||
535 | command = cmd_encrypt; | ||
536 | else if (cl.search(2, "-d", "--decrypt")) | ||
537 | command = cmd_decrypt; | ||
538 | |||
539 | if (command == cmd_none) | ||
540 | { | ||
541 | std::cerr << "No command specified." << std::endl; | ||
542 | return 2; | ||
543 | } | ||
544 | |||
545 | int mode = mode_none; | ||
546 | if (command == cmd_encrypt || command == cmd_decrypt) | ||
547 | { | ||
548 | if (!cl.search(2, "-m", "--mode")) | ||
549 | { | ||
550 | std::cerr << "The specified command requires that" | ||
551 | " a mode is specified." | ||
552 | << std::endl; | ||
553 | return 3; | ||
554 | } | ||
555 | std::string name = cl.next(""); | ||
556 | if (!name.empty()) | ||
557 | { | ||
558 | if (!stricmp(name.c_str(), "CENC")) | ||
559 | mode = mode_cenc; | ||
560 | else if (!stricmp(name.c_str(), "FRESC")) | ||
561 | mode = mode_fresc; | ||
562 | else if (!stricmp(name.c_str(), "TL")) | ||
563 | mode = mode_tl; | ||
564 | } | ||
565 | if (mode == mode_none) | ||
566 | { | ||
567 | std::cerr << "Invalid mode specified." << std::endl; | ||
568 | return 4; | ||
569 | } | ||
570 | } | ||
571 | |||
572 | bool verbose = false; | ||
573 | if (cl.search(2, "-V", "--verbose")) | ||
574 | verbose = true; | ||
575 | |||
576 | bool big_endian = false; | ||
577 | if (cl.search(2, "-b", "--big-endian")) | ||
578 | big_endian = true; | ||
579 | |||
580 | std::string infile; | ||
581 | if (cl.search(2, "-i", "--input")) | ||
582 | infile = cl.next(""); | ||
583 | if (infile.empty()) | ||
584 | { | ||
585 | std::cerr << "An input file must be specified." << std::endl; | ||
586 | return 5; | ||
587 | } | ||
588 | |||
589 | std::string outfile = infile; | ||
590 | if (cl.search(2, "-o", "--output")) | ||
591 | outfile = cl.next(outfile.c_str()); | ||
592 | |||
593 | player_info_t* pi = &players[0]; | ||
594 | std::string key; | ||
595 | if (cl.search(2, "-k", "--key")) | ||
596 | key = cl.next(""); | ||
597 | if (!key.empty()) | ||
598 | { | ||
599 | player_info_t* pitmp = find_player_info(key); | ||
600 | if (pitmp != NULL) | ||
601 | pi = pitmp; | ||
602 | else | ||
603 | { | ||
604 | static player_info_t player = { | ||
605 | NULL, key.c_str(), key.c_str(), key.c_str(), false | ||
606 | }; | ||
607 | pi = &player; | ||
608 | } | ||
609 | } | ||
610 | if (big_endian) | ||
611 | pi->big_endian = big_endian; | ||
612 | |||
613 | |||
614 | //-------------------------------------------------------------------- | ||
615 | // Read the input file. | ||
616 | //-------------------------------------------------------------------- | ||
617 | |||
618 | if (verbose) | ||
619 | std::cout << "[*] Reading input file..." << std::endl; | ||
620 | |||
621 | shared::bytes buffer; | ||
622 | if (!shared::read_file(infile, buffer)) | ||
623 | { | ||
624 | std::cerr << "Failed to read the input file." << std::endl; | ||
625 | return 6; | ||
626 | } | ||
627 | |||
628 | |||
629 | //-------------------------------------------------------------------- | ||
630 | // Process the input file. | ||
631 | //-------------------------------------------------------------------- | ||
632 | |||
633 | switch (command) | ||
634 | { | ||
635 | case cmd_sign: | ||
636 | if (verbose) | ||
637 | std::cout << "[*] Signing input file..." << std::endl; | ||
638 | if (!sign(buffer, pi, outfile, verbose)) | ||
639 | return 7; | ||
640 | std::cout << "Successfully signed the input file." << std::endl; | ||
641 | break; | ||
642 | case cmd_verify: | ||
643 | if (verbose) | ||
644 | std::cout << "[*] Verifying signature on input file..." | ||
645 | << std::endl; | ||
646 | if (!verify(buffer, pi, verbose)) | ||
647 | return 8; | ||
648 | std::cout << "Successfully verified the input file signature." | ||
649 | << std::endl; | ||
650 | break; | ||
651 | case cmd_encrypt: | ||
652 | if (verbose) | ||
653 | std::cout << "[*] Encrypting input file..." << std::endl; | ||
654 | if (!encrypt(buffer, mode, pi, outfile, verbose)) | ||
655 | return 9; | ||
656 | std::cout << "Successfully encrypted the input file." << std::endl; | ||
657 | break; | ||
658 | case cmd_decrypt: | ||
659 | if (verbose) | ||
660 | std::cout << "[*] Decrypting input file..." << std::endl; | ||
661 | if (!decrypt(buffer, mode, pi, outfile, verbose)) | ||
662 | return 10; | ||
663 | std::cout << "Successfully decrypted the input file." << std::endl; | ||
664 | break; | ||
665 | }; | ||
666 | |||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | int main(int argc, char* argv[]) | ||
671 | { | ||
672 | try | ||
673 | { | ||
674 | return process_arguments(argc, argv); | ||
675 | } | ||
676 | catch (const std::exception& xcpt) | ||
677 | { | ||
678 | std::cerr << "Exception caught: " << xcpt.what() << std::endl; | ||
679 | return -1; | ||
680 | } | ||
681 | catch (...) | ||
682 | { | ||
683 | std::cerr << "Unknown exception caught." << std::endl; | ||
684 | return -2; | ||
685 | } | ||
686 | return -3; | ||
687 | } | ||