diff options
Diffstat (limited to 'utils/zenutils/source/update_extract')
-rwxr-xr-x | utils/zenutils/source/update_extract/CMakeLists.txt | 3 | ||||
-rwxr-xr-x | utils/zenutils/source/update_extract/main.cpp | 279 |
2 files changed, 282 insertions, 0 deletions
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 | } | ||