[unshield] 01/02: New upstream version 1.4
Evgeni Golov
evgeni at moszumanska.debian.org
Mon Dec 26 13:29:39 UTC 2016
This is an automated email from the git hooks/post-receive script.
evgeni pushed a commit to branch master
in repository unshield.
commit e319415d1a38fe82d33703cc0f095c26aba73692
Author: Evgeni Golov <evgeni at debian.org>
Date: Mon Dec 26 14:27:08 2016 +0100
New upstream version 1.4
---
.gitignore | 34 ++-----
.travis.yml | 3 +-
CMakeLists.txt | 7 +-
README.md | 15 ++-
lib/convert_utf/CMakeLists.txt | 2 +-
lib/file.c | 81 ++++++++++++---
lib/helper.c | 2 +-
lib/internal.h | 2 +-
lib/libunshield.c | 10 ++
lib/libunshield.h | 3 +
lib/log.h | 8 +-
lib/md5/CMakeLists.txt | 2 +-
lib/unshield_config.h.in | 3 +
man/unshield.1 | 3 +
rebuild.sh | 6 +-
run-tests.sh | 5 +
src/CMakeLists.txt | 2 +
src/unshield-deobfuscate.c | 4 +-
src/unshield.c | 174 ++++++++++++++++++++++++++++++---
test/v0/avigomanager.md5 | 50 ++++++++++
test/v0/avigomanager.sh | 45 +++++++++
test/v5/CVE-2015-1386/CVE-2015-1386.sh | 35 +++++++
test/v5/CVE-2015-1386/data1.cab | Bin 0 -> 520 bytes
test/v5/CVE-2015-1386/data1.hdr | Bin 0 -> 3113 bytes
24 files changed, 427 insertions(+), 69 deletions(-)
diff --git a/.gitignore b/.gitignore
index a099270..38bafce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,35 +1,21 @@
-aclocal.m4
-autom4te.cache/
-config.guess
-config.log
-config.status
-config.sub
-configure
-configure.ac
-depcomp
-.deps/
-install-sh
+*.a
+**/CMakeCache.txt
+**/CMakeFiles/
+*cmake_install.cmake
+**/CMakeScripts/
+*.core
+.gdb_history
*.la
+lib/libunshield.so*
.libs
-lib/stamp-h1
-libtool
lib/unshield_config.h
libunshield.pc
*.lo
ltmain.sh
Makefile
-Makefile.in
-missing
*.o
src/unshield
src/unshield-deobfuscate
-*.core
.*.swp
-.gdb_history
-compile
-
-# CMake ignore
-**/CMakeFiles/
-**/CMakeScripts/
-*cmake_install.cmake
-**/CMakeCache.txt
+.idea
+build
diff --git a/.travis.yml b/.travis.yml
index ea293c9..ac69139 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,4 +13,5 @@ env:
- USE_OUR_OWN_MD5=1 BUILD_STATIC=1
# cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/var/tmp/unshield . && make && make install
-script: cmake -DCMAKE_INSTALL_PREFIX:PATH=/var/tmp/unshield -DUSE_OUR_OWN_MD5=$USE_OUR_OWN_MD5 -DBUILD_STATIC=$BUILD_STATIC . && make && make install
+script: mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=/var/tmp/unshield -DUSE_OUR_OWN_MD5=$USE_OUR_OWN_MD5 -DBUILD_STATIC=$BUILD_STATIC .. && make && make install && ../run-tests.sh
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c7a748b..4d43176 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ project(unshield)
# Mimic CMP0048 which is avaliable only for cmake 3.0 and later
set(PROJECT_VERSION_MAJOR 1)
-set(PROJECT_VERSION_MINOR 3)
+set(PROJECT_VERSION_MINOR 4)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
option(BUILD_STATIC "Build static version of libunshield" OFF)
@@ -27,6 +27,7 @@ check_include_files(sys/stat.h HAVE_SYS_STAT_H)
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_function_exists(fnmatch HAVE_FNMATCH)
+check_function_exists(iconv HAVE_ICONV)
set(SIZE_FORMAT "zi")
check_c_source_compiles("#include <stdio.h>\nint main(int argc, char **argv) { size_t value = 0; printf(\"%${SIZE_FORMAT}\", value); return 0; }" SIZE_FORMAT_ZI)
@@ -58,6 +59,8 @@ message(STATUS "BUILD_STATIC: ${BUILD_STATIC}")
add_definitions(-DHAVE_CONFIG_H)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/lib/unshield_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/lib/unshield_config.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libunshield.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libunshield.pc @ONLY)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/lib)
# To force position independent code for static libs on Linux x64
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
@@ -68,4 +71,4 @@ add_subdirectory(lib)
add_subdirectory(src)
install(FILES man/unshield.1 DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/man/man1)
-install(FILES libunshield.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libunshield.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
diff --git a/README.md b/README.md
index 4cfc190..a64e96b 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,17 @@
-UNSHIELD
+Unshield
========
[](https://travis-ci.org/twogood/unshield)
-DICTIONARY
+Support Unshield development
+----------------------------
+
+- [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SQ7PEFMJK36AU)
+- [Pledgie](https://pledgie.com/campaigns/29872)
+
+
+Dictionary
----------
InstallShield (IS): see www.installshield.com
@@ -14,7 +21,7 @@ InstallShield Cabinet File (ISCF): A .cab file used by IS.
Microsoft Cabinet File (MSCF): A .cab file used by Microsoft.
-ABOUT UNSHIELD
+About Unshield
--------------
To install a Pocket PC application remotely, an installable
@@ -66,7 +73,7 @@ implementation are:
- Be able to extract files from InstallShield Cabinet Files
-LICENSE
+License
-------
Unshield uses the MIT license. The short version is "do as you
diff --git a/lib/convert_utf/CMakeLists.txt b/lib/convert_utf/CMakeLists.txt
index eb60fe3..4b956e9 100644
--- a/lib/convert_utf/CMakeLists.txt
+++ b/lib/convert_utf/CMakeLists.txt
@@ -6,4 +6,4 @@ set(LIBCONVERT_UTF_SOURCES
"ConvertUTF.c"
)
-add_library(convert_utf ${LIBCONVERT_UTF_HEADES} ${LIBCONVERT_UTF_SOURCES})
\ No newline at end of file
+add_library(convert_utf STATIC ${LIBCONVERT_UTF_HEADES} ${LIBCONVERT_UTF_SOURCES})
diff --git a/lib/file.c b/lib/file.c
index f08dd7d..2dc7969 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -270,11 +270,14 @@ static int unshield_uncompress_old(Byte *dest, uLong *destLen, Byte *source, uLo
if (err != Z_OK)
return err;
- err = inflate(&stream, Z_BLOCK);
- if (err != Z_OK)
+ while (stream.avail_in > 1)
{
- inflateEnd(&stream);
- return err;
+ err = inflate(&stream, Z_BLOCK);
+ if (err != Z_OK)
+ {
+ inflateEnd(&stream);
+ return err;
+ }
}
*destLen = stream.total_out;
@@ -527,6 +530,11 @@ static bool unshield_reader_read(UnshieldReader* reader, void* buffer, size_t si
unshield_trace("Trying to read 0x%x bytes from offset %08x in volume %i",
bytes_to_read, ftell(reader->volume_file), reader->volume);
#endif
+ if (bytes_to_read == 0)
+ {
+ unshield_error("bytes_to_read can't be zero");
+ goto exit;
+ }
if (bytes_to_read != fread(p, 1, bytes_to_read, reader->volume_file))
{
@@ -596,7 +604,7 @@ static UnshieldReader* unshield_reader_create(/*{{{*/
}
/* Start with the correct volume for IS5 cabinets */
- if (reader->unshield->header_list->major_version == 5 &&
+ if (reader->unshield->header_list->major_version <= 5 &&
index > (int)reader->volume_header.last_file_index)
{
unshield_trace("Trying next volume...");
@@ -637,7 +645,7 @@ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{
FILE* output = NULL;
unsigned char* input_buffer = (unsigned char*)malloc(BUFFER_SIZE+1);
unsigned char* output_buffer = (unsigned char*)malloc(BUFFER_SIZE);
- int bytes_left;
+ unsigned int bytes_left;
uLong total_written = 0;
UnshieldReader* reader = NULL;
FileDescriptor* file_descriptor;
@@ -681,7 +689,7 @@ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{
if (filename)
{
- output = fopen(filename, "w");
+ output = fopen(filename, "wb");
if (!output)
{
unshield_error("Failed to open output file '%s'", filename);
@@ -708,14 +716,19 @@ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{
if (!unshield_reader_read(reader, &bytes_to_read, sizeof(bytes_to_read)))
{
-#if VERBOSE
- unshield_error("Failed to read %i bytes of file %i (%s) from input cabinet file %i",
+ unshield_error("Failed to read %i bytes of file %i (%s) from input cabinet file %i",
sizeof(bytes_to_read), index, unshield_file_name(unshield, index), file_descriptor->volume);
-#endif
goto exit;
}
bytes_to_read = letoh16(bytes_to_read);
+ if (bytes_to_read == 0)
+ {
+ unshield_error("bytes_to_read can't be zero");
+ unshield_error("HINT: Try unshield_file_save_old() or -O command line parameter!");
+ goto exit;
+ }
+
if (!unshield_reader_read(reader, input_buffer, bytes_to_read))
{
#if VERBOSE
@@ -734,6 +747,10 @@ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{
{
unshield_error("Decompression failed with code %i. bytes_to_read=%i, volume_bytes_left=%i, volume=%i, read_bytes=%i",
result, bytes_to_read, reader->volume_bytes_left, file_descriptor->volume, read_bytes);
+ if (result == Z_DATA_ERROR)
+ {
+ unshield_error("HINT: Try unshield_file_save_old() or -O command line parameter!");
+ }
goto exit;
}
@@ -834,7 +851,7 @@ bool unshield_file_save_raw(Unshield* unshield, int index, const char* filename)
FILE* output = NULL;
unsigned char* input_buffer = (unsigned char*)malloc(BUFFER_SIZE);
unsigned char* output_buffer = (unsigned char*)malloc(BUFFER_SIZE);
- int bytes_left;
+ unsigned int bytes_left;
UnshieldReader* reader = NULL;
FileDescriptor* file_descriptor;
@@ -874,7 +891,7 @@ bool unshield_file_save_raw(Unshield* unshield, int index, const char* filename)
if (filename)
{
- output = fopen(filename, "w");
+ output = fopen(filename, "wb");
if (!output)
{
unshield_error("Failed to open output file '%s'", filename);
@@ -950,7 +967,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
size_t input_buffer_size = BUFFER_SIZE;
unsigned char* input_buffer = (unsigned char*)malloc(BUFFER_SIZE);
unsigned char* output_buffer = (unsigned char*)malloc(BUFFER_SIZE);
- int bytes_left;
+ unsigned int bytes_left;
uLong total_written = 0;
UnshieldReader* reader = NULL;
FileDescriptor* file_descriptor;
@@ -991,7 +1008,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
if (filename)
{
- output = fopen(filename, "w");
+ output = fopen(filename, "wb");
if (!output)
{
unshield_error("Failed to open output file '%s'", filename);
@@ -1011,6 +1028,13 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
uLong bytes_to_write = 0;
int result;
+ if (reader->volume_bytes_left == 0 && !unshield_reader_open_volume(reader, reader->volume + 1))
+ {
+ unshield_error("Failed to open volume %i to read %i more bytes",
+ reader->volume + 1, bytes_left);
+ goto exit;
+ }
+
if (file_descriptor->flags & FILE_COMPRESSED)
{
static const uint8_t END_OF_CHUNK[4] = { 0x00, 0x00, 0xff, 0xff };
@@ -1053,6 +1077,33 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
chunk_size = match - chunk_buffer;
+ /*
+ Detect when the chunk actually contains the end of chunk marker.
+
+ Needed by Qtime.smk from "The Feeble Files - spanish version".
+
+ The first bit of a compressed block is always zero, so we apply this
+ workaround if it's a one.
+
+ A possibly more proper fix for this would be to have
+ unshield_uncompress_old eat compressed data and discard chunk
+ markers inbetween.
+ */
+ while ((chunk_size + sizeof(END_OF_CHUNK)) < input_size &&
+ chunk_buffer[chunk_size + sizeof(END_OF_CHUNK)] & 1)
+ {
+ unshield_warning("It seems like we have an end of chunk marker inside of a chunk.");
+ chunk_size += sizeof(END_OF_CHUNK);
+ match = find_bytes(chunk_buffer + chunk_size, input_size - chunk_size, END_OF_CHUNK, sizeof(END_OF_CHUNK));
+ if (!match)
+ {
+ unshield_error("Could not find end of chunk for file %i (%s) from input cabinet file %i",
+ index, unshield_file_name(unshield, index), file_descriptor->volume);
+ goto exit;
+ }
+ chunk_size = match - chunk_buffer;
+ }
+
#if VERBOSE >= 3
unshield_trace("chunk_size = 0x%x", chunk_size);
#endif
@@ -1066,7 +1117,7 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
if (Z_OK != result)
{
- unshield_error("Decompression failed with code %i. input_size=%i, volume_bytes_left=%i, volume=%i, read_bytes=%i",
+ unshield_error("Decompression failed with code %i. input_size=%i, volume_bytes_left=%i, volume=%i, read_bytes=%i",
result, input_size, reader->volume_bytes_left, file_descriptor->volume, read_bytes);
goto exit;
}
diff --git a/lib/helper.c b/lib/helper.c
index 77ce512..d23cca5 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -69,7 +69,7 @@ FILE* unshield_fopen_for_reading(Unshield* unshield, int index, const char* suff
#if VERBOSE
unshield_trace("Opening file '%s'", filename);
#endif
- result = fopen(filename, "r");
+ result = fopen(filename, "rb");
exit:
if (sourcedir)
diff --git a/lib/internal.h b/lib/internal.h
index 0ea88be..1f5718a 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -3,7 +3,7 @@
#define __internal_h__
#include "libunshield.h"
-#include "unshield_config.h"
+#include "lib/unshield_config.h"
#if HAVE_STDINT_H
#include <stdint.h>
diff --git a/lib/libunshield.c b/lib/libunshield.c
index 749ddac..8b10088 100644
--- a/lib/libunshield.c
+++ b/lib/libunshield.c
@@ -433,4 +433,14 @@ void unshield_close(Unshield* unshield)/*{{{*/
}
}/*}}}*/
+bool unshield_is_unicode(Unshield* unshield)
+{
+ if (unshield)
+ {
+ Header* header = unshield->header_list;
+ return header->major_version >= 17;
+ }
+ else
+ return false;
+}
diff --git a/lib/libunshield.h b/lib/libunshield.h
index 4a429e2..ee34894 100644
--- a/lib/libunshield.h
+++ b/lib/libunshield.h
@@ -93,6 +93,9 @@ bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)
/** Deobfuscate a buffer. Seed is 0 at file start */
void unshield_deobfuscate(unsigned char* buffer, size_t size, unsigned* seed);
+/** Is the archive Unicode-capable? */
+bool unshield_is_unicode(Unshield* unshield);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/log.h b/lib/log.h
index 0ab612a..37995dc 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -20,17 +20,17 @@ extern "C"
void _unshield_log(int level, const char* file, int line, const char* format, ...);
#define unshield_trace(format, args...) \
- _unshield_log(UNSHIELD_LOG_LEVEL_TRACE,__PRETTY_FUNCTION__, __LINE__, format, ##args)
+ _unshield_log(UNSHIELD_LOG_LEVEL_TRACE,__FUNCTION__, __LINE__, format, ##args)
#define unshield_warning(format, args...) \
- _unshield_log(UNSHIELD_LOG_LEVEL_WARNING,__PRETTY_FUNCTION__, __LINE__, format, ##args)
+ _unshield_log(UNSHIELD_LOG_LEVEL_WARNING,__FUNCTION__, __LINE__, format, ##args)
#define unshield_warning_unless(cond, format, args...) \
if (!(cond)) \
- _unshield_log(UNSHIELD_LOG_LEVEL_WARNING,__PRETTY_FUNCTION__, __LINE__, format, ##args)
+ _unshield_log(UNSHIELD_LOG_LEVEL_WARNING,__FUNCTION__, __LINE__, format, ##args)
#define unshield_error(format, args...) \
- _unshield_log(UNSHIELD_LOG_LEVEL_ERROR,__PRETTY_FUNCTION__, __LINE__, format, ##args)
+ _unshield_log(UNSHIELD_LOG_LEVEL_ERROR,__FUNCTION__, __LINE__, format, ##args)
#ifdef __cplusplus
}
diff --git a/lib/md5/CMakeLists.txt b/lib/md5/CMakeLists.txt
index 65a9e3a..e5b66d6 100644
--- a/lib/md5/CMakeLists.txt
+++ b/lib/md5/CMakeLists.txt
@@ -7,4 +7,4 @@ set(LIBMD5_UTF_SOURCES
"md5c.c"
)
-add_library(md5 ${LIBMD5_UTF_HEADES} ${LIBMD5_UTF_SOURCES})
\ No newline at end of file
+add_library(md5 STATIC ${LIBMD5_UTF_HEADES} ${LIBMD5_UTF_SOURCES})
diff --git a/lib/unshield_config.h.in b/lib/unshield_config.h.in
index 846ab9d..13d11c1 100644
--- a/lib/unshield_config.h.in
+++ b/lib/unshield_config.h.in
@@ -64,6 +64,9 @@
/* Define to 1 if your system has a working POSIX `fnmatch' function. */
#cmakedefine HAVE_FNMATCH 1
+/* Define to 1 if your system has a working POSIX `iconv' function. */
+#cmakedefine HAVE_ICONV 1
+
/* Defined if we should use our own MD5 routines. */
#cmakedefine01 USE_OUR_OWN_MD5
diff --git a/man/unshield.1 b/man/unshield.1
index 5bc80d7..3b6abd2 100644
--- a/man/unshield.1
+++ b/man/unshield.1
@@ -45,6 +45,9 @@ Use old compression
\fB\-r\fR
Save raw data (do not decompress)
.TP
+\fB\-R\fR
+Don't do any conversion to file and directory names when extracting.
+.TP
\fB\-v\fR
Be verbose
.TP
diff --git a/rebuild.sh b/rebuild.sh
index b26e856..869f3aa 100755
--- a/rebuild.sh
+++ b/rebuild.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+set -e
set -x
export CFLAGS="-Wall -Werror -ggdb3"
-cmake -DCMAKE_INSTALL_PREFIX:PATH=/var/tmp/unshield . && make && make install
+cd `dirname $0`
+mkdir -p build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX:PATH=/var/tmp/unshield .. && make && make install
diff --git a/run-tests.sh b/run-tests.sh
new file mode 100755
index 0000000..0e902c3
--- /dev/null
+++ b/run-tests.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+find `dirname $0`/test/v* -name '*.sh' | while read SCRIPT; do
+ echo -n "Running test $SCRIPT..."
+ bash ${SCRIPT} && echo "succeeded" || echo "FAILED with code $?"
+done
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 211d4eb..2129ed0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,3 +1,5 @@
+SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+
add_executable(unshield "unshield.c")
target_link_libraries(unshield libunshield)
diff --git a/src/unshield-deobfuscate.c b/src/unshield-deobfuscate.c
index 64e4b2f..a389f98 100644
--- a/src/unshield-deobfuscate.c
+++ b/src/unshield-deobfuscate.c
@@ -20,7 +20,7 @@ int main(int argc, char** argv)
exit(1);
}
- input = fopen(argv[1], "r");
+ input = fopen(argv[1], "rb");
if (!input)
{
fprintf(stderr,
@@ -29,7 +29,7 @@ int main(int argc, char** argv)
exit(2);
}
- output = fopen(argv[2], "w");
+ output = fopen(argv[2], "wb");
if (!output)
{
fprintf(stderr,
diff --git a/src/unshield.c b/src/unshield.c
index 296abf6..b2299fd 100644
--- a/src/unshield.c
+++ b/src/unshield.c
@@ -13,11 +13,15 @@
#include <unistd.h>
#include "../lib/libunshield.h"
#ifdef HAVE_CONFIG_H
-#include "../lib/unshield_config.h"
+#include "lib/unshield_config.h"
#endif
#if HAVE_FNMATCH
#include <fnmatch.h>
#endif
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#include <errno.h>
+#endif
#ifndef VERSION
#define VERSION "Unknown"
@@ -25,6 +29,16 @@
#define FREE(ptr) { if (ptr) { free(ptr); ptr = NULL; } }
+#ifdef _WIN32
+ #define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
+ #include <direct.h>
+ #ifndef PATH_MAX
+ #define PATH_MAX _MAX_PATH
+ #endif
+#else
+ #include <limits.h>
+#endif
+
typedef enum
{
OVERWRITE_ASK,
@@ -55,6 +69,7 @@ static const char* file_group_name = NULL;
static const char* component_name = NULL;
static bool junk_paths = false;
static bool make_lowercase = false;
+static bool raw_filename = false;
static bool verbose = false;
static ACTION action = ACTION_EXTRACT;
static OVERWRITE overwrite = OVERWRITE_ASK;
@@ -65,6 +80,10 @@ static int is_version = -1;
static const char* cab_file_name = NULL;
static char* const* path_names = NULL;
static int path_name_count = 0;
+#ifdef HAVE_ICONV
+static const char* encoding = NULL;
+iconv_t encoding_descriptor = (iconv_t)-1;
+#endif
static bool make_sure_directory_exists(const char* directory)/*{{{*/
{
@@ -114,12 +133,48 @@ exit:
return success;
}/*}}}*/
+#ifdef HAVE_ICONV
+static bool convert_encoding(char *buffer, size_t size)
+{
+ bool success = false;
+ char *newbuf, *inbuf, *outbuf;
+ size_t inbytesleft, outbytesleft, newsize;
+
+ if (encoding_descriptor == (iconv_t)-1)
+ return true;
+
+ inbuf = buffer;
+ inbytesleft = strlen(buffer);
+ newbuf = outbuf = malloc(size);
+ outbytesleft = size - 1;
+
+ if (iconv(encoding_descriptor,
+ &inbuf, &inbytesleft,
+ &outbuf, &outbytesleft) == (size_t)-1)
+ {
+ fprintf(stderr, "Could not encode text to '%s' error %s\n",
+ encoding, strerror(errno));
+ goto exit;
+ }
+
+ newsize = (size_t)(outbuf - newbuf);
+ memcpy(buffer, newbuf, newsize);
+ buffer[newsize] = '\0';
+
+ success = true;
+
+exit:
+ free(newbuf);
+ return success;
+}
+#endif
+
static void show_usage(const char* name)
{
fprintf(stderr,
"Syntax:\n"
"\n"
- "\t%s [-c COMPONENT] [-d DIRECTORY] [-D LEVEL] [-g GROUP] [-i VERSION] [-GhlOrV] c|g|l|t|x CABFILE [FILENAME...]\n"
+ "\t%s [-c COMPONENT] [-d DIRECTORY] [-D LEVEL] [-g GROUP] [-i VERSION] [-e ENCODING] [-GhlOrV] c|g|l|t|x CABFILE [FILENAME...]\n"
"\n"
"Options:\n"
"\t-c COMPONENT Only list/extract this component\n"
@@ -132,10 +187,12 @@ static void show_usage(const char* name)
"\t-g GROUP Only list/extract this file group\n"
"\t-h Show this help message\n"
"\t-i VERSION Force InstallShield version number (don't autodetect)\n"
+ "\t-e ENCODING Convert filename character encoding to local codepage from ENCODING (implicitly sets -R)\n"
"\t-j Junk paths (do not make directories)\n"
"\t-L Make file and directory names lowercase\n"
"\t-O Use old compression\n"
"\t-r Save raw data (do not decompress)\n"
+ "\t-R Don't do any conversion to file and directory names when extracting.\n"
"\t-V Print copyright and version information\n"
"\n"
"Commands:\n"
@@ -168,7 +225,7 @@ static bool handle_parameters(
{
int c;
- while ((c = getopt(argc, argv, "c:d:D:g:hi:jLnoOrV")) != -1)
+ while ((c = getopt(argc, argv, "c:d:D:g:hi:e:jLnoOrRV")) != -1)
{
switch (c)
{
@@ -192,6 +249,16 @@ static bool handle_parameters(
is_version = atoi(optarg);
break;
+ case 'e':
+#ifdef HAVE_ICONV
+ encoding = optarg;
+ raw_filename = true;
+#else
+ fprintf(stderr, "This version of Unshield is not built with encoding support.\n");
+ return false;
+#endif
+ break;
+
case 'j':
junk_paths = true;
break;
@@ -199,6 +266,10 @@ static bool handle_parameters(
case 'L':
make_lowercase = true;
break;
+
+ case 'R':
+ raw_filename = true;
+ break;
case 'n':
overwrite = OVERWRITE_NEVER;
@@ -292,6 +363,26 @@ static bool extract_file(Unshield* unshield, const char* prefix, int index)
char filename[256];
char* p;
int directory = unshield_file_directory(unshield, index);
+ long int path_max;
+ char* real_output_directory;
+ char* real_filename;
+
+ #ifdef PATH_MAX
+ path_max = PATH_MAX;
+ #else
+ path_max = pathconf(path, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 4096;
+ #endif
+
+ real_output_directory = malloc(path_max);
+ real_filename = malloc(path_max);
+ if (real_output_directory == NULL || real_filename == NULL)
+ {
+ fprintf(stderr,"Unable to allocate memory.");
+ success=false;
+ goto exit;
+ }
strcpy(dirname, output_directory);
strcat(dirname, "/");
@@ -329,14 +420,26 @@ static bool extract_file(Unshield* unshield, const char* prefix, int index)
break;
default:
- if (!isprint(*p))
- *p = '_';
- else if (make_lowercase)
- *p = tolower(*p);
+ if (!raw_filename)
+ {
+ if (!isprint(*p))
+ *p = '_';
+ else if (make_lowercase)
+ *p = tolower(*p);
+ }
break;;
}
}
+#ifdef HAVE_ICONV
+ if (!convert_encoding(dirname, sizeof(dirname)))
+ {
+ success = false;
+ goto exit;
+ }
+#endif
+
+
#if 0
if (dirname[strlen(dirname)-1] != '/')
strcat(dirname, "/");
@@ -349,10 +452,39 @@ static bool extract_file(Unshield* unshield, const char* prefix, int index)
for (p = filename + strlen(dirname); *p != '\0'; p++)
{
- if (!isprint(*p))
- *p = '_';
- else if (make_lowercase)
- *p = tolower(*p);
+ if (!raw_filename)
+ {
+ if (!isprint(*p))
+ *p = '_';
+ else if (make_lowercase)
+ *p = tolower(*p);
+ }
+ }
+
+#ifdef HAVE_ICONV
+ if (!convert_encoding(filename + strlen(dirname),
+ sizeof(filename) - strlen(dirname)))
+ {
+ success = false;
+ goto exit;
+ }
+#endif
+
+ /* use GNU extension to return non-existing files to real_output_directory */
+ realpath(output_directory, real_output_directory);
+ realpath(filename, real_filename);
+ if (real_filename == NULL || strncmp(real_filename,
+ real_output_directory,
+ strlen(real_output_directory)) != 0)
+ {
+ fprintf(stderr, "\n\nExtraction failed.\n");
+ fprintf(stderr, "Possible directory traversal attack for: %s\n", filename);
+ fprintf(stderr, "To be placed at: %s\n\n", real_filename);
+ exit_status = 1;
+ success = false;
+ free(real_filename);
+ free(real_output_directory);
+ return success;
}
printf(" extracting: %s\n", filename);
@@ -369,6 +501,7 @@ static bool extract_file(Unshield* unshield, const char* prefix, int index)
break;
}
+exit:
if (!success)
{
fprintf(stderr, "Failed to extract file '%s'.%s\n",
@@ -377,7 +510,8 @@ static bool extract_file(Unshield* unshield, const char* prefix, int index)
unlink(filename);
exit_status = 1;
}
-
+ free(real_filename);
+ free(real_output_directory);
return success;
}
@@ -582,6 +716,18 @@ int main(int argc, char* const argv[])
goto exit;
}
+#ifdef HAVE_ICONV
+ if (!unshield_is_unicode(unshield) && encoding != NULL)
+ {
+ if ((encoding_descriptor = iconv_open("", encoding)) == (iconv_t)-1)
+ {
+ fprintf(stderr, "Cannot use encoding '%s' error %s\n",
+ encoding, strerror(errno));
+ goto exit;
+ }
+ }
+#endif
+
printf("Cabinet: %s\n", cab_file_name);
switch (action)
@@ -613,6 +759,10 @@ int main(int argc, char* const argv[])
exit:
unshield_close(unshield);
+#ifdef HAVE_ICONV
+ if (encoding_descriptor != (iconv_t)-1)
+ iconv_close(encoding_descriptor);
+#endif
if (!success)
exit_status = 1;
return exit_status;
diff --git a/test/v0/avigomanager.md5 b/test/v0/avigomanager.md5
new file mode 100644
index 0000000..e638873
--- /dev/null
+++ b/test/v0/avigomanager.md5
@@ -0,0 +1,50 @@
+a943ad8f40479fa5cd68afba5787be4f ./English/Avigo100.pgm
+48c56d5db36b20d0f8644a85d1c33dac ./English/AvigoMgr.exe
+618341f3e7654c8d5d7e13f17bf433f8 ./English/AvigoToPc.avi
+c3f50ecf458c55ac1157b98f74e6ad0f ./English/Comctl32.dll
+54584845c6f232a18e4c8f7c59aeca09 ./English/cw3220.dll
+87a2adf125be51cdd5d8d3843e0f0b7e ./English/Dao2535.tlb
+0aba3f8d3a59754306d75c157e1d2b0a ./English/dao350.dll
+0be37395a851b1d7aaa7039605ec12c9 ./English/Deu100.alb
+5f854403d1e201a397151610fb9c80dd ./English/DLGDLL.dll
+72960b3faf8c1845f37d1aac23996e6c ./English/Download.exe
+cb4848abcb77130f48b8f9e9cf6d8977 ./English/Eng100.alb
+0e206fc4ef4a922c1de3199465ee5955 ./English/English/AvigoMan.cnt
+9095276ff7bdda4dd35b79d76397410c ./English/English/Avigoman.hlp
+2b212e81224f2bdd608d98fe579c8c4c ./English/Esp100.alb
+abc3474a2219fe49c2a2bf2f3e764a64 ./English/Financial100.app
+1f17ba903bc00e2694e6338c0e9bd8c3 ./English/Fra100.alb
+df1c526338995596901bcc95ed637f33 ./English/French/AvigoMan.cnt
+7265699e1bbae3022376e4f18f2e52b7 ./English/French/AVIGOMAN.HLP
+64889479798be3d1a682ebd2e1b50452 ./English/German/AvigoMan.cnt
+ec267fd5abb90d373e3b9fe6a5762315 ./English/German/Avigoman.hlp
+15f24a05040bb34765c852942480dc0d ./English/io_common.dll
+5beb2e7cb566e103480f3f4c3b99f006 ./English/io_error.dll
+b83f81c70983c28252c452fcdce906de ./English/io_ircomm.dll
+955db4b34095dc7340c82a8e328c4aa3 ./English/io_obex.dll
+989c75747c7b24caacf2e4df0330f45c ./English/io_tiobex.dll
+e21adacb76cfff3350a3e82c4f883a44 ./English/Ita100.alb
+85cf12ce9899c7242233a340dcb10de4 ./English/Italian/AvigoMan.cnt
+048fa624c7f7f9ddf76898f1dd5a5418 ./English/Italian/AVIGOMAN.HLP
+4aec6b69fd4237a2a0562974e55537ef ./English/language.lng
+8a7871c9b80a678813ca668338432456 ./English/msexcl35.dll
+e8a31571e9b0f79bc30ad7b8afa75c08 ./English/msjet35.dll
+8472c0e32802199891d76d57879bd9d9 ./English/msjint35.dll
+5773425a2bb778684b57d042a0cd5247 ./English/msjter35.dll
+6252deb3dab5e502fcab24183c642563 ./English/msltus35.dll
+d74cc7953be48ec1f3deff4741977887 ./English/msrd2x35.dll
+17291135b3146b3c3c9d201b5d65c168 ./English/mstext35.dll
+9ba25eab9b071b8ef0799f7b785c4722 ./English/Msvcrt40.dll
+81a267f80035cb3a7559be4179700931 ./English/Ole32.dll
+b9d04a19150d6799c95045719e6e6913 ./English/Oleaut32.dll
+441e965db51513b8e3c22477832641c3 ./English/Olepro32.dll
+54e9447a8133042ba0fa293a2440527b ./English/PcToAvigo.avi
+5caa91bc875bfdfd4066b1abdfcd6831 ./English/Readme.txt
+676dd602591dceb83799e58c032071f1 ./English/Spanish/AvigoMan.cnt
+cd8818345ab13e0bf7627035c8a746ad ./English/Spanish/AVIGOMAN.HLP
+77abaeafbb2340ec06bd83da4b3c0418 ./English/SyncMovie.avi
+149f277034310ea0e204a5ded4502c26 ./English/tops.dll
+9cb48c7068f6d9389493b0f1035ab204 ./English/translat.lng
+41b7178b258b97248a2e31d6771cf6f3 ./English/update.dll
+9f8c2ac5719be020bd5fe898fa01f90f ./English/vbajet32.dll
+9d1864ae5f6ff8bbde86a3f5a448110d ./English/vbar332.dll
diff --git a/test/v0/avigomanager.sh b/test/v0/avigomanager.sh
new file mode 100755
index 0000000..4e66a77
--- /dev/null
+++ b/test/v0/avigomanager.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+set -e
+cd `dirname $0`
+MD5_FILE=`pwd`/`basename $0 .sh`.md5
+UNSHIELD=/var/tmp/unshield/bin/unshield
+
+if [ \! -x ${UNSHIELD} ]; then
+ echo "unshield executable not found at $UNSHIELD" >&2
+ exit 1
+fi
+
+DIR=`mktemp -d`
+#trap 'rm -rf ${DIR}' TERM INT EXIT
+cd ${DIR}
+
+#URL=https://www.ti.com/organizers/avigo/docs/avigomanager11b22.zip
+URL="https://www.dropbox.com/s/8r4b6752swe3nhu/unshield-avigomanager11b22.zip?dl=1"
+curl -sSL -o test.zip ${URL}
+unzip -q test.zip 'data*'
+
+set +e
+timeout 10 ${UNSHIELD} -d extract1 x data1.cab > log1 2>&1
+CODE=$?
+if [ ${CODE} -ne 1 ]; then
+ cat log1 >&2
+ echo "unshield should have failed with error 1 but was $CODE" >&2
+ exit 2
+fi
+
+timeout 10 ${UNSHIELD} -O -d extract2 x data1.cab > log2 2>&1
+CODE=$?
+if [ ${CODE} -ne 0 ]; then
+ cat log2 >&2
+ echo "unshield failed with error $CODE" >&2
+ exit 3
+fi
+
+cd extract2
+find . -type f | sort | xargs md5sum > ../md5
+if ! diff ${MD5_FILE} ../md5 >&2 ; then
+ echo "MD5 sums diff" >&2
+ exit 4
+fi
+
+exit 0
\ No newline at end of file
diff --git a/test/v5/CVE-2015-1386/CVE-2015-1386.sh b/test/v5/CVE-2015-1386/CVE-2015-1386.sh
new file mode 100755
index 0000000..a04adc2
--- /dev/null
+++ b/test/v5/CVE-2015-1386/CVE-2015-1386.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+set -e
+cd `dirname $0`
+MD5_FILE=`pwd`/`basename $0 .sh`.md5
+CAB_FILE=`pwd`/data1.cab
+UNSHIELD=/var/tmp/unshield/bin/unshield
+
+if [ \! -x ${UNSHIELD} ]; then
+ echo "unshield executable not found at $UNSHIELD" >&2
+ exit 1
+fi
+
+DIR=`mktemp -d`
+#trap 'rm -rf ${DIR}' TERM INT EXIT
+cd ${DIR}
+
+set +e
+rm -f /tmp/moo
+
+timeout 10 ${UNSHIELD} -d extract1 x "$CAB_FILE" > log1 2>&1
+CODE=$?
+if [ -e /tmp/moo ]; then
+ cat log1 >&2
+ echo "unshield vulnerable to CVE-2015-1386" >&2
+ echo "See https://github.com/twogood/unshield/issues/42" >&2
+ exit 2
+fi
+
+if [ ${CODE} -ne 1 ]; then
+ cat log1 >&2
+ echo "unshield should have failed with error 1 but was $CODE" >&2
+ exit 3
+fi
+
+exit 0
diff --git a/test/v5/CVE-2015-1386/data1.cab b/test/v5/CVE-2015-1386/data1.cab
new file mode 100644
index 0000000..50c7ba1
Binary files /dev/null and b/test/v5/CVE-2015-1386/data1.cab differ
diff --git a/test/v5/CVE-2015-1386/data1.hdr b/test/v5/CVE-2015-1386/data1.hdr
new file mode 100644
index 0000000..0347550
Binary files /dev/null and b/test/v5/CVE-2015-1386/data1.hdr differ
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/unshield.git
More information about the Pkg-games-commits
mailing list