A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 409 lines 14 kB view raw
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> 23#include <file.h> 24#include <updater.h> 25#include <utils.h> 26#include <pe.h> 27 28 29static const char VERSION[] = "0.1"; 30 31void 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 40void 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 66std::string options_name(const std::string& name) 67{ 68 return shared::replace_extension(name, ".opt"); 69} 70 71std::string default_firmware_name(const std::string& name) 72{ 73 return shared::replace_extension(name, "_rk.bin"); 74} 75 76int 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()); 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 392int 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}