[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
 ========
 
 [![Build Status](https://travis-ci.org/twogood/unshield.png?branch=master)](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