diff --git a/CHANGELOG b/CHANGELOG index 53d4045..4d1ac4e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ innoextract 1.7 (TDB) - Added (preliminary) support for Inno Setup 5.6.0 installers - Added support for new GOG installers with GOG Galaxy file parts + - Added support for encrypted installers with the --password and --password-file options - Added a --show-password option to print password check information - Added a --check-password option to abort if the provided password does not match the stored checksum - Fixed building in paths that contain regex expressions diff --git a/README.md b/README.md index 03c2fcf..00ef05b 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,6 @@ Documentation is also available as a man page: * Names for data slice/disk files in multi-file installers must follow the standard naming scheme. -* Encrypted installers are not supported. - A perhaps more complete, but Windows-only, tool to extract Inno Setup files is [innounp](http://innounp.sourceforge.net/). Extracting Windows installer executables created by programs other than Inno Setup is out of the scope of this project. Some of these can be unpacked by the following programs: diff --git a/doc/innoextract.1 b/doc/innoextract.1 index 3754127..df0befc 100644 --- a/doc/innoextract.1 +++ b/doc/innoextract.1 @@ -204,7 +204,7 @@ Specifies the password to decrypt encrypted files. The password is assumed to be Use the \fB\-\-password-file\fP option to load the password from a file or standard input instead. This option cannot be combined with \fB\-\-password-file\fP. -Use the \fB\-\-check\-password\fP option to abort processing entirely if the password is incorrect. +If this password does not match the checksum stored in the installer, encrypted files will be skipped but unencrypted files will still be extracted. Use the \fB\-\-check\-password\fP option to abort processing entirely if the password is incorrect. .TP \fB\-\-password-file\fP \fIFILE\fP Load a password form the specified file. Only the first line excluding the terminating carriage return and/or line break is used as the password. The password is assumed to be encoded as UTF-8 and converted the internal according used in the installer as needed. @@ -213,7 +213,7 @@ If the special file name "\fB-\fP" is used, the password will be read from stand Use the \fB\-\-password\fP option to specify the password on the command\-line instead. This option cannot be combined with \fB\-\-password\fP. -Use the \fB\-\-check\-password\fP option to abort processing entirely if the password is incorrect. +If this password does not match the checksum stored in the installer, encrypted files will be skipped but unencrypted files will still be extracted. Use the \fB\-\-check\-password\fP option to abort processing entirely if the password is incorrect. .TP \fB\-p\fP, \fB\-\-progress\fP[=\fIENABLE\fP] By default \fBinnoextract\fP will try to detect if the terminal supports shell escape codes and enable or disable progress bar output accordingly. Pass \fB1\fP or \fBtrue\fP to \fB\-\-progress\fP to force progress bar output. Pass \fB0\fP or \fBfalse\fP to never show a progress bar. @@ -290,8 +290,6 @@ Included scripts and checks are not executed. The mapping from Inno Setup constants like the application directory to subdirectories is hard-coded. Names for data slice/disk files in multi-file installers must follow the standard naming scheme. - -Encrypted installers are not supported. .SH SEE ALSO \fBcabextract\fP(1), \fBunar\fP(1), \fBunrar\fP(1), \fBunshield\fP(1), \fBtzset\fP(3) .SH BUGS diff --git a/src/cli/extract.cpp b/src/cli/extract.cpp index 5ef5441..c33eef3 100644 --- a/src/cli/extract.cpp +++ b/src/cli/extract.cpp @@ -881,8 +881,12 @@ void process_file(const fs::path & file, const extract_options & o) { bool multiple_sections = print_file_info(o, info); - if(!o.password.empty()) { - std::string password; + std::string password; + if(o.password.empty()) { + if(!o.quiet && (o.list || o.test || o.extract) && (info.header.options & setup::header::EncryptionUsed)) { + log_warning << "Setup contains encrypted files, use the --password option to extract them"; + } + } else { util::from_utf8(o.password, password, info.version.codepage()); if(info.header.options & setup::header::Password) { crypto::hasher checksum(info.header.password.type); @@ -894,8 +898,15 @@ void process_file(const fs::path & file, const extract_options & o) { } else { log_error << "Incorrect password provided"; } + password.clear(); } } + #if !INNOEXTRACT_HAVE_ARC4 + if((o.extract || o.test) && (info.header.options & setup::header::EncryptionUsed)) { + log_warning << "ARC4 decryption not supported in this build, skipping compressed chunks"; + } + password.clear(); + #endif } if(!o.list && !o.test && !o.extract) { @@ -1015,8 +1026,8 @@ void process_file(const fs::path & file, const extract_options & o) { << ']'); stream::chunk_reader::pointer chunk_source; - if((o.extract || o.test) && chunk.first.encryption == stream::Plaintext) { - chunk_source = stream::chunk_reader::get(*slice_reader, chunk.first, std::string()); + if((o.extract || o.test) && (chunk.first.encryption == stream::Plaintext || !password.empty())) { + chunk_source = stream::chunk_reader::get(*slice_reader, chunk.first, password); } boost::uint64_t offset = 0; @@ -1058,7 +1069,11 @@ void process_file(const fs::path & file, const extract_options & o) { named = true; } if(chunk.first.encryption != stream::Plaintext) { - std::cout << '"' << color::dim_yellow << output.first->path() << color::reset << '"'; + if(password.empty()) { + std::cout << '"' << color::dim_yellow << output.first->path() << color::reset << '"'; + } else { + std::cout << '"' << color::yellow << output.first->path() << color::reset << '"'; + } } else { std::cout << '"' << color::white << output.first->path() << color::reset << '"'; } @@ -1069,7 +1084,7 @@ void process_file(const fs::path & file, const extract_options & o) { if(!o.quiet) { print_size_info(file, size); } - if(chunk.first.encryption != stream::Plaintext) { + if(chunk.first.encryption != stream::Plaintext && password.empty()) { std::cout << " - encrypted"; } std::cout << '\n';