1 /* zenutils - Utilities for working with creative firmwares.
2 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com>
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.
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.
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
22 #include <getpot/GetPot>
29 static const char VERSION
[] = "0.1";
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
;
43 std::cout
<< std::endl
44 << "Usage: update_patch [command] [options]" << 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
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
66 std::string
options_name(const std::string
& name
)
68 return shared::replace_extension(name
, ".opt");
71 std::string
default_firmware_name(const std::string
& name
)
73 return shared::replace_extension(name
, "_rk.bin");
76 int process_arguments(int argc
, char* argv
[])
78 //--------------------------------------------------------------------
79 // Parse input variables.
80 //--------------------------------------------------------------------
82 GetPot
cl(argc
, argv
);
83 if (cl
.size() == 1 || cl
.search(2, "-h", "--help"))
89 std::string updatername
;
90 if (cl
.search("-u") || cl
.search("--updater"))
91 updatername
= cl
.next("");
92 if (updatername
.empty())
94 std::cerr
<< "Updater executable must be specified." << std::endl
;
99 if (cl
.search("-V") || cl
.search("--verbose"))
103 std::cout
<< "[*] Parsing options file..." << std::endl
;
105 GetPot
optfile(options_name(updatername
.c_str()).c_str());
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", "");
115 if (cl
.search("-f") || cl
.search("--firmware"))
116 firmwarename
= cl
.next(firmwarename
.c_str());
119 if (cl
.search("-o") || cl
.search("--offset"))
120 offset
= cl
.next("");
122 if (offset
.empty() && !offset_pa
)
125 std::cout
<< "[*] Looking for firmware archive offset..."
129 if (!zen::find_firmware_archive(updatername
, offset_va
, offset_pa
))
131 std::cerr
<< "Failed to find the firmware archive offset."
139 if (!sscanf(offset
.c_str(), "0x%x", &offset_val
))
141 if (!sscanf(offset
.c_str(), "0x%X", &offset_val
))
143 std::cerr
<< "\'" << offset
144 << "\' is not a valid c-style hexadecimal value."
149 offset_pa
= static_cast<dword
>(offset_val
);
155 std::cout
<< "[*] Looking for firmware archive key..."
157 shared::bytes buffer
;
158 if (!shared::read_file(updatername
, buffer
))
160 std::cerr
<< "Failed to read the firmware updater executable."
164 key
= zen::find_firmware_key(&buffer
[0], buffer
.size());
167 std::cerr
<< "Failed to find the firmware archive key."
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
;
190 //--------------------------------------------------------------------
191 // Prepare the firmware archive for being patched into the updater.
192 //--------------------------------------------------------------------
195 std::cout
<< "[*] Reading firmware archive..." << std::endl
;
197 shared::bytes buffer
;
198 if (!shared::read_file(firmwarename
, buffer
))
200 std::cerr
<< "Failed to read the firmware archive." << std::endl
;
205 std::cout
<< " Bytes read: "
206 << std::hex
<< std::showbase
<< std::setw(10)
207 << std::setfill('0') << std::internal
208 << buffer
.size() << std::endl
;
211 std::cout
<< "[*] Compressing firmware archive..." << std::endl
;
213 std::string compfirmware
= shared::replace_extension(firmwarename
, ".def");
214 if (!shared::deflate_to_file(buffer
, compfirmware
.c_str()))
216 std::cerr
<< "Failed to compress the firmware archive." << std::endl
;
221 std::cout
<< "[*] Reading compressed firmware archive..." << std::endl
;
223 if (!shared::read_file(compfirmware
, buffer
))
225 std::cerr
<< "Failed to read the compressed firmware archive."
231 std::cout
<< " Bytes read: "
232 << std::hex
<< std::showbase
<< std::setw(10)
233 << std::setfill('0') << std::internal
234 << buffer
.size() << std::endl
;
236 // Delete the temporary firmware file.
237 std::remove(compfirmware
.c_str());
240 std::cout
<< "[*] Encrypting compressed firmware archive..."
243 if (!zen::crypt_firmware(key
.c_str(), &buffer
[0], buffer
.size()))
245 std::cerr
<< "Failed to encrypt the compressed firmware archive."
251 //--------------------------------------------------------------------
252 // Backup the updater and patch the firmware archive into it.
253 //--------------------------------------------------------------------
256 std::cout
<< "[*] Backing up the updater executable..." << std::endl
;
258 if (!shared::backup_file(updatername
))
260 std::cerr
<< "Failed to backup the updater executable." << std::endl
;
264 // Is there enough space within the existing firmware archive
265 // to hold the new one?
266 if (size
< buffer
.size())
268 // No, we need to add a new section to hold the new firmware archive.
270 std::cout
<< "[*] Adding new section to the updater executable..."
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]);
278 // Read the updater portable executable.
280 if (!pef
.read(updatername
))
282 std::cerr
<< "Failed to read the updater portable executable"
283 " structure." << std::endl
;
287 // Add a new section to the updater, containing the encrypted
289 shared::section_info newsection
;
290 if (!pef
.add_section(".firm", newbuffer
, newsection
))
292 std::cerr
<< "Failed to add an extra section to the updater"
293 " executable." << std::endl
;
298 std::cout
<< "[*] Relocating code references to the firmware"
299 " archive..." << std::endl
;
301 // Locate the code section.
302 shared::section_info textsection
;
303 if (!pef
.find_section(".text", textsection
))
305 std::cerr
<< "Failed to find the code section in the updater"
306 " executable." << std::endl
;
310 // Read the code section data.
311 if (!shared::read_file(updatername
, buffer
, textsection
.raw_address
,
312 textsection
.raw_size
))
314 std::cerr
<< "Failed to read the code section from the updater"
315 " executable." << std::endl
;
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
)
324 std::cerr
<< "Failed to compute address of the new or old"
325 " archive." << std::endl
;
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
++)
333 dword val
= *(dword
*)&buffer
[i
];
334 if (val
>= oldva
&& val
<= (oldva
+ 3))
336 *(dword
*)&buffer
[i
] = newva
+ (val
- oldva
);
339 << std::hex
<< std::showbase
<< std::setw(10)
340 << std::setfill('0') << std::internal
341 << (imgbase
+ textsection
.virtual_address
+ i
)
343 << std::hex
<< std::showbase
<< std::setw(10)
344 << std::setfill('0') << std::internal
347 << std::hex
<< std::showbase
<< std::setw(10)
348 << std::setfill('0') << std::internal
349 << (newva
+ (val
- oldva
)) << std::endl
;
353 // Write the relocated code section data.
354 if (!shared::write_file(updatername
, buffer
, false, textsection
.raw_address
,
357 std::cerr
<< "Failed to write the relocated code section to the"
358 " updater executable." << std::endl
;
361 } //if (size < buffer.size())
364 // Yes, overwrite the existing firmware archive.
366 std::cout
<< "[*] Overwriting existing firmware archive..."
369 shared::bytes
archive_size(sizeof(dword
));
370 *(dword
*)&archive_size
[0] = buffer
.size();
372 if (!shared::write_file(updatername
, archive_size
, false, offset_pa
,
373 archive_size
.size()))
375 std::cerr
<< "Failed to write archive size to the updater"
376 " executable." << std::endl
;
380 if (!shared::write_file(updatername
, buffer
, false,
381 offset_pa
+archive_size
.size(), buffer
.size()))
383 std::cerr
<< "Failed to write the new archive to the updater"
384 " exectuable." << std::endl
;
392 int main(int argc
, char* argv
[])
396 return process_arguments(argc
, argv
);
398 catch (const std::exception
& xcpt
)
400 std::cerr
<< "Exception caught: " << xcpt
.what() << std::endl
;
405 std::cerr
<< "Unknown exception caught." << std::endl
;