pax_global_header00006660000000000000000000000064130367443370014524gustar00rootroot0000000000000052 comment=1e7ed752952f7f9fd9a51347e33ec3160b6ba26d unshield-1.4.2/000077500000000000000000000000001303674433700133435ustar00rootroot00000000000000unshield-1.4.2/.gitignore000066400000000000000000000003701303674433700153330ustar00rootroot00000000000000*.a **/CMakeCache.txt **/CMakeFiles/ *cmake_install.cmake **/CMakeScripts/ *.core .gdb_history *.la lib/libunshield.so* .libs lib/unshield_config.h libunshield.pc *.lo ltmain.sh Makefile *.o src/unshield src/unshield-deobfuscate .*.swp .idea build unshield-1.4.2/.travis.yml000066400000000000000000000010651303674433700154560ustar00rootroot00000000000000language: c compiler: - gcc - clang env: global: - CFLAGS="-Wall -Werror -ggdb3" matrix: - USE_OUR_OWN_MD5=0 BUILD_STATIC=0 - USE_OUR_OWN_MD5=1 BUILD_STATIC=0 - USE_OUR_OWN_MD5=0 BUILD_STATIC=1 - USE_OUR_OWN_MD5=1 BUILD_STATIC=1 # cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/var/tmp/unshield . && 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 unshield-1.4.2/CMakeLists.txt000066400000000000000000000057511303674433700161130ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.7) project(unshield) # Mimic CMP0048 which is avaliable only for cmake 3.0 and later set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 4) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") option(BUILD_STATIC "Build static version of libunshield" OFF) include(CheckIncludeFiles) include(CheckFunctionExists) include(CheckCSourceCompiles) include(GNUInstallDirs) check_include_files(byteswap.h HAVE_BYTESWAP_H) check_include_files(dlfcn.h HAVE_DLFCN_H) check_include_files(inttypes.h HAVE_INTTYPES_H) check_include_files(memory.h HAVE_MEMORY_H) check_include_files(stdbool.h HAVE_STDBOOL_H) check_include_files(stdint.h HAVE_STDINT_H) check_include_files(stdlib.h HAVE_STDLIB_H) check_include_files(strings.h HAVE_STRINGS_H) check_include_files(string.h HAVE_STRING_H) check_include_files(sys/byteswap.h HAVE_SYS_BYTESWAP_H) 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 \nint main(int argc, char **argv) { size_t value = 0; printf(\"%${SIZE_FORMAT}\", value); return 0; }" SIZE_FORMAT_ZI) if(NOT SIZE_FORMAT_ZI) set(SIZE_FORMAT "i") check_c_source_compiles("#include \nint main(int argc, char **argv) { size_t value = 0; printf(\"%${SIZE_FORMAT}\", value); return 0; }" SIZE_FORMAT_I) if(NOT SIZE_FORMAT_I) set(SIZE_FORMAT "li") check_c_source_compiles("#include \nint main(int argc, char **argv) { size_t value = 0; printf(\"%${SIZE_FORMAT}\", value); return 0; }" SIZE_FORMAT_LI) if(NOT SIZE_FORMAT_LI) message(FATAL_ERROR "You must be using a really weird platform!") endif() endif() endif() find_package(ZLIB REQUIRED) find_package(OpenSSL) if (${OPENSSL_FOUND}) option(USE_OUR_OWN_MD5 "Build using own md5 implementation" OFF) else() option(USE_OUR_OWN_MD5 "Build using own md5 implementation" ON) endif() message(STATUS "OPENSSL_FOUND: ${OPENSSL_FOUND}") message(STATUS "USE_OUR_OWN_MD5: ${USE_OUR_OWN_MD5}") 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) # The POSITION_INDEPENDENT_CODE property was introduced in cmake 2.8.10/CMP0018 # as we are targeting cmake 2.8.7, we can't use # set(CMAKE_POSITION_INDEPENDENT_CODE ON) # let's fall back to add_definitions for now add_definitions(-fPIC) add_subdirectory(lib) add_subdirectory(src) install(FILES man/unshield.1 DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/man/man1) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libunshield.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) unshield-1.4.2/ChangeLog000066400000000000000000000013311303674433700151130ustar00rootroot000000000000002009-07-16 Mark Ellis * 0.6 release 2009-06-18 Mark Ellis * src/unshield.c - fix use of -L (lowercase) option with -d 2008-05-06 Jonny Lamb * .cvsignore: * cvsclean: * lib/.cvsignore: * lib/md5/.cvsignore: * src/.cvsignore: Removed useless CVS ignore and clean files. * bootstrap: * unshield.spec.in: Removed spec file. 2008-05-06 Jonny Lamb * VERSION: Upped version number to 0.5.1. 2008-02-15 Mark Ellis * added man page for unshield 2008-01-09 Mark Ellis * started changelog * added LICENSE to EXTRA_DIST * added cabfile.h to libunshield_la_SOURCES unshield-1.4.2/LICENSE000066400000000000000000000021031303674433700143440ustar00rootroot00000000000000Copyright (c) 2003 David Eriksson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. unshield-1.4.2/README.md000066400000000000000000000053331303674433700146260ustar00rootroot00000000000000Unshield ======== [![Build Status](https://travis-ci.org/twogood/unshield.png?branch=master)](https://travis-ci.org/twogood/unshield) 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 InstallShield Cabinet File (ISCF): A .cab file used by IS. Microsoft Cabinet File (MSCF): A .cab file used by Microsoft. About Unshield -------------- To install a Pocket PC application remotely, an installable Microsoft Cabinet File is copied to the /Windows/AppMgr/Install directory on the PDA and then the wceload.exe is executed to perform the actual install. That is a very simple procedure. Unfortunately, many applications for Pocket PC are distributed as InstallShield installers for Microsoft Windows, and not as individual Microsoft Cabinet Files. That is very impractical for users of other operating systems, such as Linux or FreeBSD. An installer created by the InstallShield software stores the files it will install inside of InstallShield Cabinet Files. It would thus be desirable to be able to extract the Microsoft Cabinet Files from the InstallShield Cabinet Files in order to be able to install the applications without access to Microsoft Windows. The format of InstallShield Cabinet Files is not officially documented but there are two tools available for Microsoft Windows that extracts files from InstallShield installers, and they are distributed with source code included. These tools are named "i5comp" and "i6comp" and can be downloaded from the Internet. One major drawback with these tools are that for the actual decompression of the files stored in the InstallShield Cabinet Files they require the use of code written by InstallShield that is not available as source code. Luckily, by examining this code with the 'strings' tool, I discovered that they were using the open source zlib library (www.gzip.org/zlib) for decompression. I could have modified i5comp and i6comp to run on other operating systems than Microsoft Windows, but I preferred to use them as a reference for this implementation. The goals of this implementation are: - Use a well known open source license (MIT) - Work on both little-endian and big-endian systems - Separate the implementation in a tool and a library - Support InstallShield versions 5 and later - Be able to list contents of InstallShield Cabinet Files - Be able to extract files from InstallShield Cabinet Files License ------- Unshield uses the MIT license. The short version is "do as you like, but don't blame me if anything goes wrong". See the file LICENSE for details. unshield-1.4.2/lib/000077500000000000000000000000001303674433700141115ustar00rootroot00000000000000unshield-1.4.2/lib/CMakeLists.txt000066400000000000000000000021271303674433700166530ustar00rootroot00000000000000add_subdirectory(convert_utf) if(USE_OUR_OWN_MD5) add_subdirectory(md5) endif() set(LIBUNSHIELD_HEADES "internal.h" "libunshield.h" "log.h" "cabfile.h" ) set(LIBUNSHIELD_SOURCES "bswap.c" "component.c" "directory.c" "file.c" "file_group.c" "helper.c" "libunshield.c" "log.c" ) if(BUILD_STATIC) set(LIBUNSHIELD_LIBRARY_TYPE STATIC) else() set(LIBUNSHIELD_LIBRARY_TYPE SHARED) endif() add_library(libunshield ${LIBUNSHIELD_LIBRARY_TYPE} ${LIBUNSHIELD_HEADES} ${LIBUNSHIELD_SOURCES}) if(USE_OUR_OWN_MD5) target_link_libraries(libunshield ${ZLIB_LIBRARY} md5 convert_utf) else() target_link_libraries(libunshield ${ZLIB_LIBRARY} ${OPENSSL_LIBRARIES} convert_utf) endif() set_target_properties(libunshield PROPERTIES OUTPUT_NAME unshield) set_target_properties(libunshield PROPERTIES VERSION 0.0.0 SOVERSION 0) install(TARGETS libunshield RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES libunshield.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})unshield-1.4.2/lib/bswap.c000066400000000000000000000006041303674433700153710ustar00rootroot00000000000000/* $Id$ */ #include "internal.h" #if IMPLEMENT_BSWAP_XX /* * Written by Manuel Bouyer . * Public domain. */ uint16_t bswap_16(uint16_t x) { return ((x << 8) & 0xff00) | ((x >> 8) & 0x00ff); } uint32_t bswap_32(uint32_t x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } #endif unshield-1.4.2/lib/cabfile.h000066400000000000000000000042401303674433700156470ustar00rootroot00000000000000/* $Id$ */ #ifndef __cabfile_h__ #define __cabfile_h__ #include "internal.h" #define OFFSET_COUNT 0x47 #define CAB_SIGNATURE 0x28635349 #define MSCF_SIGNATURE 0x4643534d #define COMMON_HEADER_SIZE 20 #define VOLUME_HEADER_SIZE_V5 40 #define VOLUME_HEADER_SIZE_V6 64 #define MAX_FILE_GROUP_COUNT 71 #define MAX_COMPONENT_COUNT 71 typedef struct { uint32_t signature; /* 00 */ uint32_t version; uint32_t volume_info; uint32_t cab_descriptor_offset; uint32_t cab_descriptor_size; /* 10 */ } CommonHeader; typedef struct { uint32_t data_offset; uint32_t data_offset_high; uint32_t first_file_index; uint32_t last_file_index; uint32_t first_file_offset; uint32_t first_file_offset_high; uint32_t first_file_size_expanded; uint32_t first_file_size_expanded_high; uint32_t first_file_size_compressed; uint32_t first_file_size_compressed_high; uint32_t last_file_offset; uint32_t last_file_offset_high; uint32_t last_file_size_expanded; uint32_t last_file_size_expanded_high; uint32_t last_file_size_compressed; uint32_t last_file_size_compressed_high; } VolumeHeader; typedef struct { uint32_t file_table_offset; /* c */ uint32_t file_table_size; /* 14 */ uint32_t file_table_size2; /* 18 */ uint32_t directory_count; /* 1c */ uint32_t file_count; /* 28 */ uint32_t file_table_offset2; /* 2c */ uint32_t file_group_offsets[MAX_FILE_GROUP_COUNT]; /* 0x3e */ uint32_t component_offsets [MAX_COMPONENT_COUNT]; /* 0x15a */ } CabDescriptor; #define FILE_SPLIT 1 #define FILE_OBFUSCATED 2 #define FILE_COMPRESSED 4 #define FILE_INVALID 8 #define LINK_NONE 0 #define LINK_PREV 1 #define LINK_NEXT 2 #define LINK_BOTH 3 typedef struct { uint32_t name_offset; uint32_t directory_index; uint16_t flags; uint32_t expanded_size; uint32_t compressed_size; uint32_t data_offset; uint8_t md5[16]; uint16_t volume; uint32_t link_previous; uint32_t link_next; uint8_t link_flags; } FileDescriptor; typedef struct { uint32_t name_offset; uint32_t descriptor_offset; uint32_t next_offset; } OffsetList; #endif unshield-1.4.2/lib/component.c000066400000000000000000000031321303674433700162560ustar00rootroot00000000000000/* $Id$ */ #include "internal.h" #include "log.h" #include #include int unshield_component_count(Unshield* unshield) { Header* header = unshield->header_list; return header->component_count; } const char* unshield_component_name(Unshield* unshield, int index) { Header* header = unshield->header_list; if (index >= 0 && index < header->component_count) return header->components[index]->name; else return NULL; } UnshieldComponent* unshield_component_new(Header* header, uint32_t offset) { UnshieldComponent* self = NEW1(UnshieldComponent); uint8_t* p = unshield_header_get_buffer(header, offset); uint32_t file_group_table_offset; unsigned i; self->name = unshield_header_get_string(header, READ_UINT32(p)); p += 4; switch (header->major_version) { case 0: case 5: p += 0x6c; break; case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: default: p += 0x6b; break; } self->file_group_count = READ_UINT16(p); p += 2; if (self->file_group_count > MAX_FILE_GROUP_COUNT) abort(); self->file_group_names = NEW(const char*, self->file_group_count); file_group_table_offset = READ_UINT32(p); p += 4; p = unshield_header_get_buffer(header, file_group_table_offset); for (i = 0; i < self->file_group_count; i++) { self->file_group_names[i] = unshield_header_get_string(header, READ_UINT32(p)); p += 4; } return self; } void unshield_component_destroy(UnshieldComponent* self) { if (self) { FREE(self->file_group_names); free(self); } } unshield-1.4.2/lib/convert_utf/000077500000000000000000000000001303674433700164475ustar00rootroot00000000000000unshield-1.4.2/lib/convert_utf/CMakeLists.txt000066400000000000000000000002641303674433700212110ustar00rootroot00000000000000set(LIBCONVERT_UTF_HEADES "ConvertUTF.h" ) set(LIBCONVERT_UTF_SOURCES "ConvertUTF.c" ) add_library(convert_utf STATIC ${LIBCONVERT_UTF_HEADES} ${LIBCONVERT_UTF_SOURCES}) unshield-1.4.2/lib/convert_utf/ConvertUTF.c000066400000000000000000000451731303674433700206240ustar00rootroot00000000000000/* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ /* --------------------------------------------------------------------- Conversions between UTF32, UTF-16, and UTF-8. Source code file. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Sept 2001: fixed const & error conditions per mods suggested by S. Parent & A. Lillich. June 2002: Tim Dodd added detection and handling of incomplete source sequences, enhanced error detection, added casts to eliminate compiler warnings. July 2003: slight mods to back out aggressive FFFE detection. Jan 2004: updated switches in from-UTF8 conversions. Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. See the header file "ConvertUTF.h" for complete documentation. ------------------------------------------------------------------------ */ #include "ConvertUTF.h" #ifdef CVTUTF_DEBUG #include #endif static const int halfShift = 10; /* used for shifting by 10 bits */ static const UTF32 halfBase = 0x0010000UL; static const UTF32 halfMask = 0x3FFUL; #define UNI_SUR_HIGH_START (UTF32)0xD800 #define UNI_SUR_HIGH_END (UTF32)0xDBFF #define UNI_SUR_LOW_START (UTF32)0xDC00 #define UNI_SUR_LOW_END (UTF32)0xDFFF #define false 0 #define true 1 /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF16 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; UTF16* target = *targetStart; while (source < sourceEnd) { UTF32 ch; if (target >= targetEnd) { result = targetExhausted; break; } ch = *source++; if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = (UTF16)ch; /* normal case */ } } else if (ch > UNI_MAX_LEGAL_UTF32) { if (flags == strictConversion) { result = sourceIllegal; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ if (target + 1 >= targetEnd) { --source; /* Back up source pointer! */ result = targetExhausted; break; } ch -= halfBase; *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF32 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; UTF32* target = *targetStart; UTF32 ch, ch2; while (source < sourceEnd) { const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } else { /* We don't have the 16 bits following the high surrogate. */ --source; /* return to the high surrogate */ result = sourceExhausted; break; } } else if (flags == strictConversion) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } if (target >= targetEnd) { source = oldSource; /* Back up source pointer! */ result = targetExhausted; break; } *target++ = ch; } *sourceStart = source; *targetStart = target; #ifdef CVTUTF_DEBUG if (result == sourceIllegal) { fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); fflush(stderr); } #endif return result; } /* --------------------------------------------------------------------- */ /* * Index into the table below with the first byte of a UTF-8 sequence to * get the number of trailing bytes that are supposed to follow it. * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is * left as-is for anyone who may want to do such conversion, which was * allowed in earlier algorithms. */ static const char trailingBytesForUTF8[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; /* * Magic values subtracted from a buffer value during UTF8 conversion. * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed * into the first byte, depending on how many bytes follow. There are * as many entries in this table as there are UTF-8 sequence types. * (I.e., one byte sequence, two byte... etc.). Remember that sequencs * for *legal* UTF-8 will be 4 or fewer bytes total. */ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; /* --------------------------------------------------------------------- */ /* The interface converts a whole buffer to avoid function-call overhead. * Constants have been gathered. Loops & conditionals have been removed as * much as possible for efficiency, in favor of drop-through switches. * (See "Note A" at the bottom of the file for equivalent code.) * If your compiler supports it, the "isLegalUTF8" call can be turned * into an inline function. */ /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF8 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; UTF8* target = *targetStart; while (source < sourceEnd) { UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; const UTF32 byteMark = 0x80; const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { UTF32 ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } else { /* We don't have the 16 bits following the high surrogate. */ --source; /* return to the high surrogate */ result = sourceExhausted; break; } } else if (flags == strictConversion) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } /* Figure out how many bytes the result will require */ if (ch < (UTF32)0x80) { bytesToWrite = 1; } else if (ch < (UTF32)0x800) { bytesToWrite = 2; } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; } else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; } target += bytesToWrite; if (target > targetEnd) { source = oldSource; /* Back up source pointer! */ target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) { /* note: everything falls through. */ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ /* * Utility routine to tell whether a sequence of bytes is legal UTF-8. * This must be called with the length pre-determined by the first byte. * If not calling this from ConvertUTF8to*, then the length can be set by: * length = trailingBytesForUTF8[*source]+1; * and the sequence is illegal right away if there aren't that many bytes * available. * If presented with a length > 4, this returns false. The Unicode * definition of UTF-8 goes up to 4-byte sequences. */ static Boolean isLegalUTF8(const UTF8 *source, int length) { UTF8 a; const UTF8 *srcptr = source+length; switch (length) { default: return false; /* Everything else falls through when "true"... */ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 2: if ((a = (*--srcptr)) > 0xBF) return false; switch (*source) { /* no fall-through in this inner switch */ case 0xE0: if (a < 0xA0) return false; break; case 0xED: if (a > 0x9F) return false; break; case 0xF0: if (a < 0x90) return false; break; case 0xF4: if (a > 0x8F) return false; break; default: if (a < 0x80) return false; } case 1: if (*source >= 0x80 && *source < 0xC2) return false; } if (*source > 0xF4) return false; return true; } /* --------------------------------------------------------------------- */ /* * Exported function to return whether a UTF-8 sequence is legal or not. * This is not used here; it's just exported. */ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { int length = trailingBytesForUTF8[*source]+1; if (source+length > sourceEnd) { return false; } return isLegalUTF8(source, length); } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF16 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; UTF16* target = *targetStart; while (source < sourceEnd) { UTF32 ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8(source, extraBytesToRead+1)) { result = sourceIllegal; break; } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 3: ch += *source++; ch <<= 6; case 2: ch += *source++; ch <<= 6; case 1: ch += *source++; ch <<= 6; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { source -= (extraBytesToRead+1); /* Back up source pointer! */ result = targetExhausted; break; } if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { source -= (extraBytesToRead+1); /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = (UTF16)ch; /* normal case */ } } else if (ch > UNI_MAX_UTF16) { if (flags == strictConversion) { result = sourceIllegal; source -= (extraBytesToRead+1); /* return to the start */ break; /* Bail out; shouldn't continue */ } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ if (target + 1 >= targetEnd) { source -= (extraBytesToRead+1); /* Back up source pointer! */ result = targetExhausted; break; } ch -= halfBase; *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF8 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; UTF8* target = *targetStart; while (source < sourceEnd) { UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; const UTF32 byteMark = 0x80; ch = *source++; if (flags == strictConversion ) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } /* * Figure out how many bytes the result will require. Turn any * illegally large UTF32 things (> Plane 17) into replacement chars. */ if (ch < (UTF32)0x80) { bytesToWrite = 1; } else if (ch < (UTF32)0x800) { bytesToWrite = 2; } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; } else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; result = sourceIllegal; } target += bytesToWrite; if (target > targetEnd) { --source; /* Back up source pointer! */ target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) { /* note: everything falls through. */ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF32 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; UTF32* target = *targetStart; while (source < sourceEnd) { UTF32 ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8(source, extraBytesToRead+1)) { result = sourceIllegal; break; } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; case 4: ch += *source++; ch <<= 6; case 3: ch += *source++; ch <<= 6; case 2: ch += *source++; ch <<= 6; case 1: ch += *source++; ch <<= 6; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { source -= (extraBytesToRead+1); /* Back up the source pointer! */ result = targetExhausted; break; } if (ch <= UNI_MAX_LEGAL_UTF32) { /* * UTF-16 surrogate values are illegal in UTF-32, and anything * over Plane 17 (> 0x10FFFF) is illegal. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { source -= (extraBytesToRead+1); /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = ch; } } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ result = sourceIllegal; *target++ = UNI_REPLACEMENT_CHAR; } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- Note A. The fall-through switches in UTF-8 reading code save a temp variable, some decrements & conditionals. The switches are equivalent to the following loop: { int tmpBytesToRead = extraBytesToRead+1; do { ch += *source++; --tmpBytesToRead; if (tmpBytesToRead) ch <<= 6; } while (tmpBytesToRead > 0); } In UTF-8 writing code, the switches on "bytesToWrite" are similarly unrolled loops. --------------------------------------------------------------------- */ unshield-1.4.2/lib/convert_utf/ConvertUTF.h000066400000000000000000000134651303674433700206300ustar00rootroot00000000000000/* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ /* --------------------------------------------------------------------- Conversions between UTF32, UTF-16, and UTF-8. Header file. Several funtions are included here, forming a complete set of conversions between the three formats. UTF-7 is not included here, but is handled in a separate source file. Each of these routines takes pointers to input buffers and output buffers. The input buffers are const. Each routine converts the text between *sourceStart and sourceEnd, putting the result into the buffer between *targetStart and targetEnd. Note: the end pointers are *after* the last item: e.g. *(sourceEnd - 1) is the last item. The return result indicates whether the conversion was successful, and if not, whether the problem was in the source or target buffers. (Only the first encountered problem is indicated.) After the conversion, *sourceStart and *targetStart are both updated to point to the end of last text successfully converted in the respective buffers. Input parameters: sourceStart - pointer to a pointer to the source buffer. The contents of this are modified on return so that it points at the next thing to be converted. targetStart - similarly, pointer to pointer to the target buffer. sourceEnd, targetEnd - respectively pointers to the ends of the two buffers, for overflow checking only. These conversion functions take a ConversionFlags argument. When this flag is set to strict, both irregular sequences and isolated surrogates will cause an error. When the flag is set to lenient, both irregular sequences and isolated surrogates are converted. Whether the flag is strict or lenient, all illegal sequences will cause an error return. This includes sequences such as: , , or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code must check for illegal sequences. When the flag is set to lenient, characters over 0x10FFFF are converted to the replacement character; otherwise (when the flag is set to strict) they constitute an error. Output parameters: The value "sourceIllegal" is returned from some routines if the input sequence is malformed. When "sourceIllegal" is returned, the source value will point to the illegal value that caused the problem. E.g., in UTF-8 when a sequence is malformed, it points to the start of the malformed sequence. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Fixes & updates, Sept 2001. ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- The following 4 definitions are compiler-specific. The C standard does not guarantee that wchar_t has at least 16 bits, so wchar_t is no less portable than unsigned short! All should be unsigned values to avoid sign extension during bit mask & shift operations. ------------------------------------------------------------------------ */ typedef unsigned long UTF32; /* at least 32 bits */ typedef unsigned short UTF16; /* at least 16 bits */ typedef unsigned char UTF8; /* typically 8 bits */ typedef unsigned char Boolean; /* 0 or 1 */ /* Some fundamental constants */ #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD #define UNI_MAX_BMP (UTF32)0x0000FFFF #define UNI_MAX_UTF16 (UTF32)0x0010FFFF #define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF typedef enum { conversionOK, /* conversion successful */ sourceExhausted, /* partial character in source, but hit end */ targetExhausted, /* insuff. room in target for conversion */ sourceIllegal /* source sequence is illegal/malformed */ } ConversionResult; typedef enum { strictConversion = 0, lenientConversion } ConversionFlags; /* This is for C++ and does no harm in C */ #ifdef __cplusplus extern "C" { #endif ConversionResult ConvertUTF8toUTF16 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF8 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF8toUTF32 ( const UTF8** sourceStart, const UTF8* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF8 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF32 ( const UTF16** sourceStart, const UTF16* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF16 ( const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); #ifdef __cplusplus } #endif /* --------------------------------------------------------------------- */ unshield-1.4.2/lib/convert_utf/README.google000066400000000000000000000004611303674433700206030ustar00rootroot00000000000000This is a utf8/16/32 conversion functions downloaded from unicode.org website from url: ftp://www.unicode.org/Public/PROGRAMS/CVTUTF/ Only ConvertUTF.h and ConvertUTF.c files were downloaded. The rest of files related to UTF7 and testing harness were not downloaded. No modifications have been done. unshield-1.4.2/lib/convert_utf/README.unshield000066400000000000000000000001571303674433700211440ustar00rootroot00000000000000These files were downloaded from http://gears.googlecode.com/svn/trunk/third_party/convert_utf/ on 2013-02-15. unshield-1.4.2/lib/convert_utf/readme.txt000066400000000000000000000027241303674433700204520ustar00rootroot00000000000000 The accompanying C source code file "ConvertUTF.c" and the associated header file "ConvertUTF.h" provide for conversion between various transformation formats of Unicode characters. The following conversions are supported: UTF-32 to UTF-16 UTF-32 to UTF-8 UTF-16 to UTF-32 UTF-16 to UTF-8 UTF-8 to UTF-16 UTF-8 to UTF-32 In addition, there is a test harness which runs various tests. The files "CVTUTF7.C" and "CVTUTF7.H" are for archival and historical purposes only. They have not been updated to Unicode 3.0 or later and should be considered obsolescent. "CVTUTF7.C" contains two functions that can convert between UCS2 (i.e., the BMP characters only) and UTF-7. Surrogates are not supported, the code has not been tested, and should be considered unsuitable for general purpose use. Please submit any bug reports about these programs here: http://www.unicode.org/unicode/reporting.html Version 1.0: initial version. Version 1.1: corrected some minor problems; added stricter checks. Version 1.2: corrected switch statements associated with "extraBytesToRead" in 4 & 5 byte cases, in functions for conversion from UTF8. Note: formally, the 4 & 5 byte cases are illegal in the latest UTF8, but the table and this code has always catered for those, cases since at one time they were legal. Version 1.3: Updated UTF-8 legality check; updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions Updated UTF-8 legality tests in harness.c Last update: October 19, 2004 unshield-1.4.2/lib/directory.c000066400000000000000000000014361303674433700162650ustar00rootroot00000000000000/* $Id$ */ #include "internal.h" #include "log.h" int unshield_directory_count(Unshield* unshield) { if (unshield) { /* XXX: multi-volume support... */ Header* header = unshield->header_list; return header->cab.directory_count; } else return -1; } const char* unshield_directory_name(Unshield* unshield, int index) { if (unshield && index >= 0) { /* XXX: multi-volume support... */ Header* header = unshield->header_list; if (index < (int)header->cab.directory_count) return unshield_get_utf8_string(header, header->data + header->common.cab_descriptor_offset + header->cab.file_table_offset + header->file_table[index]); } unshield_warning("Failed to get directory name %i", index); return NULL; } unshield-1.4.2/lib/file.c000066400000000000000000001004771303674433700152050ustar00rootroot00000000000000/* $Id$ */ #include "internal.h" #if USE_OUR_OWN_MD5 #include "md5/global.h" #include "md5/md5.h" #else #include #define MD5Init MD5_Init #define MD5Update MD5_Update #define MD5Final MD5_Final #endif #include "cabfile.h" #include "log.h" #include #include #include #include /* for MIN(a,b) */ #ifndef MIN /* missing in some platforms */ #define MIN(a,b) (((a)<(b))?(a):(b)) #endif #include #define VERBOSE 3 #define ror8(x,n) (((x) >> ((int)(n))) | ((x) << (8 - (int)(n)))) #define rol8(x,n) (((x) << ((int)(n))) | ((x) >> (8 - (int)(n)))) static FileDescriptor* unshield_read_file_descriptor(Unshield* unshield, int index) { /* XXX: multi-volume support... */ Header* header = unshield->header_list; uint8_t* p = NULL; uint8_t* saved_p = NULL; FileDescriptor* fd = NEW1(FileDescriptor); switch (header->major_version) { case 0: case 5: saved_p = p = header->data + header->common.cab_descriptor_offset + header->cab.file_table_offset + header->file_table[header->cab.directory_count + index]; #if VERBOSE unshield_trace("File descriptor offset %i: %08x", index, p - header->data); #endif fd->volume = header->index; fd->name_offset = READ_UINT32(p); p += 4; fd->directory_index = READ_UINT32(p); p += 4; fd->flags = READ_UINT16(p); p += 2; fd->expanded_size = READ_UINT32(p); p += 4; fd->compressed_size = READ_UINT32(p); p += 4; p += 0x14; fd->data_offset = READ_UINT32(p); p += 4; #if VERBOSE >= 2 unshield_trace("Name offset: %08x", fd->name_offset); unshield_trace("Directory index: %08x", fd->directory_index); unshield_trace("Flags: %04x", fd->flags); unshield_trace("Expanded size: %08x", fd->expanded_size); unshield_trace("Compressed size: %08x", fd->compressed_size); unshield_trace("Data offset: %08x", fd->data_offset); #endif if (header->major_version == 5) { memcpy(fd->md5, p, 0x10); p += 0x10; assert((p - saved_p) == 0x3a); } break; case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: default: saved_p = p = header->data + header->common.cab_descriptor_offset + header->cab.file_table_offset + header->cab.file_table_offset2 + index * 0x57; #if VERBOSE unshield_trace("File descriptor offset: %08x", p - header->data); #endif fd->flags = READ_UINT16(p); p += 2; fd->expanded_size = READ_UINT32(p); p += 4; p += 4; fd->compressed_size = READ_UINT32(p); p += 4; p += 4; fd->data_offset = READ_UINT32(p); p += 4; p += 4; memcpy(fd->md5, p, 0x10); p += 0x10; p += 0x10; fd->name_offset = READ_UINT32(p); p += 4; fd->directory_index = READ_UINT16(p); p += 2; assert((p - saved_p) == 0x40); p += 0xc; fd->link_previous = READ_UINT32(p); p += 4; fd->link_next = READ_UINT32(p); p += 4; fd->link_flags = *p; p ++; #if VERBOSE if (fd->link_flags != LINK_NONE) { unshield_trace("Link: previous=%i, next=%i, flags=%i", fd->link_previous, fd->link_next, fd->link_flags); } #endif fd->volume = READ_UINT16(p); p += 2; assert((p - saved_p) == 0x57); break; } if (!(fd->flags & FILE_COMPRESSED) && fd->compressed_size != fd->expanded_size) { unshield_warning("File is not compressed but compressed size is %08x and expanded size is %08x", fd->compressed_size, fd->expanded_size); } return fd; } static FileDescriptor* unshield_get_file_descriptor(Unshield* unshield, int index) { /* XXX: multi-volume support... */ Header* header = unshield->header_list; if (index < 0 || index >= (int)header->cab.file_count) { unshield_error("Invalid index"); return NULL; } if (!header->file_descriptors) header->file_descriptors = calloc(header->cab.file_count, sizeof(FileDescriptor*)); if (!header->file_descriptors[index]) header->file_descriptors[index] = unshield_read_file_descriptor(unshield, index); return header->file_descriptors[index]; } int unshield_file_count (Unshield* unshield)/*{{{*/ { if (unshield) { /* XXX: multi-volume support... */ Header* header = unshield->header_list; return header->cab.file_count; } else return -1; }/*}}}*/ const char* unshield_file_name (Unshield* unshield, int index)/*{{{*/ { FileDescriptor* fd = unshield_get_file_descriptor(unshield, index); if (fd) { /* XXX: multi-volume support... */ Header* header = unshield->header_list; return unshield_get_utf8_string(header, header->data + header->common.cab_descriptor_offset + header->cab.file_table_offset + fd->name_offset); } unshield_warning("Failed to get file descriptor %i", index); return NULL; }/*}}}*/ bool unshield_file_is_valid(Unshield* unshield, int index) { bool is_valid = false; FileDescriptor* fd; if (index < 0 || index >= unshield_file_count(unshield)) goto exit; if (!(fd = unshield_get_file_descriptor(unshield, index))) goto exit; if (fd->flags & FILE_INVALID) goto exit; if (!fd->name_offset) goto exit; if (!fd->data_offset) goto exit; is_valid = true; exit: return is_valid; } static int unshield_uncompress (Byte *dest, uLong* destLen, Byte *source, uLong *sourceLen)/*{{{*/ { z_stream stream; int err; stream.next_in = source; stream.avail_in = (uInt)*sourceLen; stream.next_out = dest; stream.avail_out = (uInt)*destLen; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; /* make second parameter negative to disable checksum verification */ err = inflateInit2(&stream, -MAX_WBITS); if (err != Z_OK) return err; err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); return err; } *destLen = stream.total_out; *sourceLen = stream.total_in; err = inflateEnd(&stream); return err; }/*}}}*/ static int unshield_uncompress_old(Byte *dest, uLong *destLen, Byte *source, uLong *sourceLen)/*{{{*/ { z_stream stream; int err; stream.next_in = source; stream.avail_in = (uInt)*sourceLen; stream.next_out = dest; stream.avail_out = (uInt)*destLen; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; *destLen = 0; *sourceLen = 0; /* make second parameter negative to disable checksum verification */ err = inflateInit2(&stream, -MAX_WBITS); if (err != Z_OK) return err; while (stream.avail_in > 1) { err = inflate(&stream, Z_BLOCK); if (err != Z_OK) { inflateEnd(&stream); return err; } } *destLen = stream.total_out; *sourceLen = stream.total_in; err = inflateEnd(&stream); return err; }/*}}}*/ typedef struct { Unshield* unshield; unsigned index; FileDescriptor* file_descriptor; int volume; FILE* volume_file; VolumeHeader volume_header; unsigned volume_bytes_left; unsigned obfuscation_offset; } UnshieldReader; static bool unshield_reader_open_volume(UnshieldReader* reader, int volume)/*{{{*/ { bool success = false; unsigned data_offset = 0; unsigned volume_bytes_left_compressed; unsigned volume_bytes_left_expanded; CommonHeader common_header; #if VERBOSE >= 2 unshield_trace("Open volume %i", volume); #endif FCLOSE(reader->volume_file); reader->volume_file = unshield_fopen_for_reading(reader->unshield, volume, CABINET_SUFFIX); if (!reader->volume_file) { unshield_error("Failed to open input cabinet file %i", volume); goto exit; } { uint8_t tmp[COMMON_HEADER_SIZE]; uint8_t* p = tmp; if (COMMON_HEADER_SIZE != fread(&tmp, 1, COMMON_HEADER_SIZE, reader->volume_file)) goto exit; if (!unshield_read_common_header(&p, &common_header)) goto exit; } memset(&reader->volume_header, 0, sizeof(VolumeHeader)); switch (reader->unshield->header_list->major_version) { case 0: case 5: { uint8_t five_header[VOLUME_HEADER_SIZE_V5]; uint8_t* p = five_header; if (VOLUME_HEADER_SIZE_V5 != fread(&five_header, 1, VOLUME_HEADER_SIZE_V5, reader->volume_file)) goto exit; reader->volume_header.data_offset = READ_UINT32(p); p += 4; #if VERBOSE if (READ_UINT32(p)) unshield_trace("Unknown = %08x", READ_UINT32(p)); #endif /* unknown */ p += 4; reader->volume_header.first_file_index = READ_UINT32(p); p += 4; reader->volume_header.last_file_index = READ_UINT32(p); p += 4; reader->volume_header.first_file_offset = READ_UINT32(p); p += 4; reader->volume_header.first_file_size_expanded = READ_UINT32(p); p += 4; reader->volume_header.first_file_size_compressed = READ_UINT32(p); p += 4; reader->volume_header.last_file_offset = READ_UINT32(p); p += 4; reader->volume_header.last_file_size_expanded = READ_UINT32(p); p += 4; reader->volume_header.last_file_size_compressed = READ_UINT32(p); p += 4; if (reader->volume_header.last_file_offset == 0) reader->volume_header.last_file_offset = INT32_MAX; } break; case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: default: { uint8_t six_header[VOLUME_HEADER_SIZE_V6]; uint8_t* p = six_header; if (VOLUME_HEADER_SIZE_V6 != fread(&six_header, 1, VOLUME_HEADER_SIZE_V6, reader->volume_file)) goto exit; reader->volume_header.data_offset = READ_UINT32(p); p += 4; reader->volume_header.data_offset_high = READ_UINT32(p); p += 4; reader->volume_header.first_file_index = READ_UINT32(p); p += 4; reader->volume_header.last_file_index = READ_UINT32(p); p += 4; reader->volume_header.first_file_offset = READ_UINT32(p); p += 4; reader->volume_header.first_file_offset_high = READ_UINT32(p); p += 4; reader->volume_header.first_file_size_expanded = READ_UINT32(p); p += 4; reader->volume_header.first_file_size_expanded_high = READ_UINT32(p); p += 4; reader->volume_header.first_file_size_compressed = READ_UINT32(p); p += 4; reader->volume_header.first_file_size_compressed_high = READ_UINT32(p); p += 4; reader->volume_header.last_file_offset = READ_UINT32(p); p += 4; reader->volume_header.last_file_offset_high = READ_UINT32(p); p += 4; reader->volume_header.last_file_size_expanded = READ_UINT32(p); p += 4; reader->volume_header.last_file_size_expanded_high = READ_UINT32(p); p += 4; reader->volume_header.last_file_size_compressed = READ_UINT32(p); p += 4; reader->volume_header.last_file_size_compressed_high = READ_UINT32(p); p += 4; } break; } #if VERBOSE >= 2 unshield_trace("First file index = %i, last file index = %i", reader->volume_header.first_file_index, reader->volume_header.last_file_index); unshield_trace("First file offset = %08x, last file offset = %08x", reader->volume_header.first_file_offset, reader->volume_header.last_file_offset); #endif /* enable support for split archives for IS5 */ if (reader->unshield->header_list->major_version == 5) { if (reader->index < (reader->unshield->header_list->cab.file_count - 1) && reader->index == reader->volume_header.last_file_index && reader->volume_header.last_file_size_compressed != reader->file_descriptor->compressed_size) { unshield_trace("IS5 split file last in volume"); reader->file_descriptor->flags |= FILE_SPLIT; } else if (reader->index > 0 && reader->index == reader->volume_header.first_file_index && reader->volume_header.first_file_size_compressed != reader->file_descriptor->compressed_size) { unshield_trace("IS5 split file first in volume"); reader->file_descriptor->flags |= FILE_SPLIT; } } if (reader->file_descriptor->flags & FILE_SPLIT) { #if VERBOSE unshield_trace(/*"Total bytes left = 0x08%x, "*/"previous data offset = 0x08%x", /*total_bytes_left, */data_offset); #endif if (reader->index == reader->volume_header.last_file_index && reader->volume_header.last_file_offset != 0x7FFFFFFF) { /* can be first file too... */ #if VERBOSE unshield_trace("Index %i is last file in cabinet file %i", reader->index, volume); #endif data_offset = reader->volume_header.last_file_offset; volume_bytes_left_expanded = reader->volume_header.last_file_size_expanded; volume_bytes_left_compressed = reader->volume_header.last_file_size_compressed; } else if (reader->index == reader->volume_header.first_file_index) { #if VERBOSE unshield_trace("Index %i is first file in cabinet file %i", reader->index, volume); #endif data_offset = reader->volume_header.first_file_offset; volume_bytes_left_expanded = reader->volume_header.first_file_size_expanded; volume_bytes_left_compressed = reader->volume_header.first_file_size_compressed; } else { success = true; goto exit; } #if VERBOSE unshield_trace("Will read 0x%08x bytes from offset 0x%08x", volume_bytes_left_compressed, data_offset); #endif } else { data_offset = reader->file_descriptor->data_offset; volume_bytes_left_expanded = reader->file_descriptor->expanded_size; volume_bytes_left_compressed = reader->file_descriptor->compressed_size; } if (reader->file_descriptor->flags & FILE_COMPRESSED) reader->volume_bytes_left = volume_bytes_left_compressed; else reader->volume_bytes_left = volume_bytes_left_expanded; fseek(reader->volume_file, data_offset, SEEK_SET); reader->volume = volume; success = true; exit: return success; }/*}}}*/ void unshield_deobfuscate(unsigned char* buffer, size_t size, unsigned* seed) { unsigned tmp_seed = *seed; for (; size > 0; size--, buffer++, tmp_seed++) { *buffer = ror8(*buffer ^ 0xd5, 2) - (tmp_seed % 0x47); } *seed = tmp_seed; } static void unshield_reader_deobfuscate(UnshieldReader* reader, uint8_t* buffer, size_t size) { unshield_deobfuscate(buffer, size, &reader->obfuscation_offset); } static bool unshield_reader_read(UnshieldReader* reader, void* buffer, size_t size)/*{{{*/ { bool success = false; uint8_t* p = buffer; size_t bytes_left = size; #if VERBOSE >= 3 unshield_trace("unshield_reader_read start: bytes_left = 0x%x, volume_bytes_left = 0x%x", bytes_left, reader->volume_bytes_left); #endif for (;;) { /* Read as much as possible from this volume */ size_t bytes_to_read = MIN(bytes_left, reader->volume_bytes_left); #if VERBOSE >= 3 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)) { unshield_error("Failed to read 0x%08x bytes of file %i (%s) from volume %i. Current offset = 0x%08x", bytes_to_read, reader->index, unshield_file_name(reader->unshield, reader->index), reader->volume, ftell(reader->volume_file)); goto exit; } bytes_left -= bytes_to_read; reader->volume_bytes_left -= bytes_to_read; #if VERBOSE >= 3 unshield_trace("bytes_left = %i, volume_bytes_left = %i", bytes_left, reader->volume_bytes_left); #endif if (!bytes_left) break; p += bytes_to_read; /* Open next volume */ if (!unshield_reader_open_volume(reader, reader->volume + 1)) { unshield_error("Failed to open volume %i to read %i more bytes", reader->volume + 1, bytes_to_read); goto exit; } } if (reader->file_descriptor->flags & FILE_OBFUSCATED) unshield_reader_deobfuscate(reader, buffer, size); success = true; exit: return success; }/*}}}*/ static UnshieldReader* unshield_reader_create(/*{{{*/ Unshield* unshield, int index, FileDescriptor* file_descriptor) { bool success = false; UnshieldReader* reader = NEW1(UnshieldReader); if (!reader) return NULL; reader->unshield = unshield; reader->index = index; reader->file_descriptor = file_descriptor; for (;;) { if (!unshield_reader_open_volume(reader, file_descriptor->volume)) { unshield_error("Failed to open volume %i", file_descriptor->volume); goto exit; } /* Start with the correct volume for IS5 cabinets */ if (reader->unshield->header_list->major_version <= 5 && index > (int)reader->volume_header.last_file_index) { unshield_trace("Trying next volume..."); file_descriptor->volume++; continue; } break; }; success = true; exit: if (success) return reader; FREE(reader); return NULL; }/*}}}*/ static void unshield_reader_destroy(UnshieldReader* reader)/*{{{*/ { if (reader) { FCLOSE(reader->volume_file); free(reader); } }/*}}}*/ #define BUFFER_SIZE (64*1024) /* * If filename is NULL, just throw away the result */ bool unshield_file_save (Unshield* unshield, int index, const char* filename)/*{{{*/ { bool success = false; FILE* output = NULL; unsigned char* input_buffer = (unsigned char*)malloc(BUFFER_SIZE+1); unsigned char* output_buffer = (unsigned char*)malloc(BUFFER_SIZE); unsigned int bytes_left; uLong total_written = 0; UnshieldReader* reader = NULL; FileDescriptor* file_descriptor; MD5_CTX md5; MD5Init(&md5); if (!unshield) goto exit; if (!(file_descriptor = unshield_get_file_descriptor(unshield, index))) { unshield_error("Failed to get file descriptor for file %i", index); goto exit; } if ((file_descriptor->flags & FILE_INVALID) || 0 == file_descriptor->data_offset) { /* invalid file */ goto exit; } if (file_descriptor->link_flags & LINK_PREV) { success = unshield_file_save(unshield, file_descriptor->link_previous, filename); goto exit; } reader = unshield_reader_create(unshield, index, file_descriptor); if (!reader) { unshield_error("Failed to create data reader for file %i", index); goto exit; } if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset) { unshield_error("File %i is not inside the cabinet.", index); goto exit; } if (filename) { output = fopen(filename, "wb"); if (!output) { unshield_error("Failed to open output file '%s'", filename); goto exit; } } if (file_descriptor->flags & FILE_COMPRESSED) bytes_left = file_descriptor->compressed_size; else bytes_left = file_descriptor->expanded_size; /*unshield_trace("Bytes to read: %i", bytes_left);*/ while (bytes_left > 0) { uLong bytes_to_write = BUFFER_SIZE; int result; if (file_descriptor->flags & FILE_COMPRESSED) { uLong read_bytes; uint16_t bytes_to_read = 0; if (!unshield_reader_read(reader, &bytes_to_read, sizeof(bytes_to_read))) { 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); 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 unshield_error("Failed to read %i bytes of file %i (%s) from input cabinet file %i", bytes_to_read, index, unshield_file_name(unshield, index), file_descriptor->volume); #endif goto exit; } /* add a null byte to make inflate happy */ input_buffer[bytes_to_read] = 0; read_bytes = bytes_to_read+1; result = unshield_uncompress(output_buffer, &bytes_to_write, input_buffer, &read_bytes); if (Z_OK != result) { 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; } #if VERBOSE >= 3 unshield_trace("read_bytes = %i", read_bytes); #endif bytes_left -= 2; bytes_left -= bytes_to_read; } else { bytes_to_write = MIN(bytes_left, BUFFER_SIZE); if (!unshield_reader_read(reader, output_buffer, bytes_to_write)) { #if VERBOSE unshield_error("Failed to read %i bytes from input cabinet file %i", bytes_to_write, file_descriptor->volume); #endif goto exit; } bytes_left -= bytes_to_write; } MD5Update(&md5, output_buffer, bytes_to_write); if (output) { if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output)) { unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename); goto exit; } } total_written += bytes_to_write; } if (file_descriptor->expanded_size != total_written) { unshield_error("Expanded size expected to be %i, but was %i", file_descriptor->expanded_size, total_written); goto exit; } if (unshield->header_list->major_version >= 6) { unsigned char md5result[16]; MD5Final(md5result, &md5); if (0 != memcmp(md5result, file_descriptor->md5, 16)) { unshield_error("MD5 checksum failure for file %i (%s)", index, unshield_file_name(unshield, index)); goto exit; } } success = true; exit: unshield_reader_destroy(reader); FCLOSE(output); FREE(input_buffer); FREE(output_buffer); return success; }/*}}}*/ int unshield_file_directory(Unshield* unshield, int index)/*{{{*/ { FileDescriptor* fd = unshield_get_file_descriptor(unshield, index); if (fd) { return fd->directory_index; } else return -1; }/*}}}*/ size_t unshield_file_size(Unshield* unshield, int index)/*{{{*/ { FileDescriptor* fd = unshield_get_file_descriptor(unshield, index); if (fd) { return fd->expanded_size; } else return 0; }/*}}}*/ bool unshield_file_save_raw(Unshield* unshield, int index, const char* filename) { /* XXX: Thou Shalt Not Cut & Paste... */ bool success = false; FILE* output = NULL; unsigned char* input_buffer = (unsigned char*)malloc(BUFFER_SIZE); unsigned char* output_buffer = (unsigned char*)malloc(BUFFER_SIZE); unsigned int bytes_left; UnshieldReader* reader = NULL; FileDescriptor* file_descriptor; if (!unshield) goto exit; if (!(file_descriptor = unshield_get_file_descriptor(unshield, index))) { unshield_error("Failed to get file descriptor for file %i", index); goto exit; } if ((file_descriptor->flags & FILE_INVALID) || 0 == file_descriptor->data_offset) { /* invalid file */ goto exit; } if (file_descriptor->link_flags & LINK_PREV) { success = unshield_file_save_raw(unshield, file_descriptor->link_previous, filename); goto exit; } reader = unshield_reader_create(unshield, index, file_descriptor); if (!reader) { unshield_error("Failed to create data reader for file %i", index); goto exit; } if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset) { unshield_error("File %i is not inside the cabinet.", index); goto exit; } if (filename) { output = fopen(filename, "wb"); if (!output) { unshield_error("Failed to open output file '%s'", filename); goto exit; } } if (file_descriptor->flags & FILE_COMPRESSED) bytes_left = file_descriptor->compressed_size; else bytes_left = file_descriptor->expanded_size; /*unshield_trace("Bytes to read: %i", bytes_left);*/ while (bytes_left > 0) { uLong bytes_to_write = MIN(bytes_left, BUFFER_SIZE); if (!unshield_reader_read(reader, output_buffer, bytes_to_write)) { #if VERBOSE unshield_error("Failed to read %i bytes from input cabinet file %i", bytes_to_write, file_descriptor->volume); #endif goto exit; } bytes_left -= bytes_to_write; if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output)) { unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename); goto exit; } } success = true; exit: unshield_reader_destroy(reader); FCLOSE(output); FREE(input_buffer); FREE(output_buffer); return success; } static uint8_t* find_bytes( const uint8_t* buffer, size_t bufferSize, const uint8_t* pattern, size_t patternSize) { const void *p = buffer; size_t buffer_left = bufferSize; while ((p = memchr(p, pattern[0], buffer_left)) != NULL) { if (patternSize > buffer_left) break; if (memcmp(p, pattern, patternSize) == 0) return (uint8_t*)p; ++p; --buffer_left; } return NULL; } bool unshield_file_save_old(Unshield* unshield, int index, const char* filename)/*{{{*/ { /* XXX: Thou Shalt Not Cut & Paste... */ bool success = false; FILE* output = NULL; 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); unsigned int bytes_left; uLong total_written = 0; UnshieldReader* reader = NULL; FileDescriptor* file_descriptor; if (!unshield) goto exit; if (!(file_descriptor = unshield_get_file_descriptor(unshield, index))) { unshield_error("Failed to get file descriptor for file %i", index); goto exit; } if ((file_descriptor->flags & FILE_INVALID) || 0 == file_descriptor->data_offset) { /* invalid file */ goto exit; } if (file_descriptor->link_flags & LINK_PREV) { success = unshield_file_save(unshield, file_descriptor->link_previous, filename); goto exit; } reader = unshield_reader_create(unshield, index, file_descriptor); if (!reader) { unshield_error("Failed to create data reader for file %i", index); goto exit; } if (unshield_fsize(reader->volume_file) == (long)file_descriptor->data_offset) { unshield_error("File %i is not inside the cabinet.", index); goto exit; } if (filename) { output = fopen(filename, "wb"); if (!output) { unshield_error("Failed to open output file '%s'", filename); goto exit; } } if (file_descriptor->flags & FILE_COMPRESSED) bytes_left = file_descriptor->compressed_size; else bytes_left = file_descriptor->expanded_size; /*unshield_trace("Bytes to read: %i", bytes_left);*/ while (bytes_left > 0) { 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 }; uLong read_bytes; size_t input_size = reader->volume_bytes_left; uint8_t* chunk_buffer; while (input_size > input_buffer_size) { input_buffer_size *= 2; #if VERBOSE >= 3 unshield_trace("increased input_buffer_size to 0x%x", input_buffer_size); #endif input_buffer = realloc(input_buffer, input_buffer_size); assert(input_buffer); } if (!unshield_reader_read(reader, input_buffer, input_size)) { #if VERBOSE unshield_error("Failed to read 0x%x bytes of file %i (%s) from input cabinet file %i", input_size, index, unshield_file_name(unshield, index), file_descriptor->volume); #endif goto exit; } bytes_left -= input_size; for (chunk_buffer = input_buffer; input_size; ) { size_t chunk_size; uint8_t* match = find_bytes(chunk_buffer, input_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; /* 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 /* add a null byte to make inflate happy */ chunk_buffer[chunk_size] = 0; bytes_to_write = BUFFER_SIZE; read_bytes = chunk_size; result = unshield_uncompress_old(output_buffer, &bytes_to_write, chunk_buffer, &read_bytes); if (Z_OK != result) { 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; } #if VERBOSE >= 3 unshield_trace("read_bytes = 0x%x", read_bytes); #endif chunk_buffer += chunk_size; chunk_buffer += sizeof(END_OF_CHUNK); input_size -= chunk_size; input_size -= sizeof(END_OF_CHUNK); if (output) if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output)) { unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename); goto exit; } total_written += bytes_to_write; } } else { bytes_to_write = MIN(bytes_left, BUFFER_SIZE); if (!unshield_reader_read(reader, output_buffer, bytes_to_write)) { #if VERBOSE unshield_error("Failed to read %i bytes from input cabinet file %i", bytes_to_write, file_descriptor->volume); #endif goto exit; } bytes_left -= bytes_to_write; if (output) if (bytes_to_write != fwrite(output_buffer, 1, bytes_to_write, output)) { unshield_error("Failed to write %i bytes to file '%s'", bytes_to_write, filename); goto exit; } total_written += bytes_to_write; } } if (file_descriptor->expanded_size != total_written) { unshield_error("Expanded size expected to be %i, but was %i", file_descriptor->expanded_size, total_written); goto exit; } success = true; exit: unshield_reader_destroy(reader); FCLOSE(output); FREE(input_buffer); FREE(output_buffer); return success; }/*}}}*/ unshield-1.4.2/lib/file_group.c000066400000000000000000000034401303674433700164110ustar00rootroot00000000000000/* $Id$ */ #include "internal.h" #include "log.h" #include #include #define VERBOSE 1 UnshieldFileGroup* unshield_file_group_new(Header* header, uint32_t offset)/*{{{*/ { UnshieldFileGroup* self = NEW1(UnshieldFileGroup); uint8_t* p = unshield_header_get_buffer(header, offset); #if VERBOSE unshield_trace("File group descriptor offset: %08x", offset); #endif self->name = unshield_header_get_string(header, READ_UINT32(p)); p += 4; if (header->major_version == 5) p += 0x48; else p += 0x12; self->first_file = READ_UINT32(p); p += 4; self->last_file = READ_UINT32(p); p += 4; #if VERBOSE unshield_trace("File group %08x first file = %i, last file = %i", offset, self->first_file, self->last_file); #endif return self; }/*}}}*/ void unshield_file_group_destroy(UnshieldFileGroup* self)/*{{{*/ { FREE(self); }/*}}}*/ int unshield_file_group_count(Unshield* unshield)/*{{{*/ { Header* header = unshield->header_list; return header->file_group_count; }/*}}}*/ UnshieldFileGroup* unshield_file_group_get(Unshield* unshield, int index) { Header* header = unshield->header_list; if (index >= 0 && index < header->file_group_count) return header->file_groups[index]; else return NULL; } UnshieldFileGroup* unshield_file_group_find(Unshield* unshield, const char* name) { Header* header = unshield->header_list; int i; for (i = 0; i < header->file_group_count; i++) { if (STREQ(header->file_groups[i]->name, name)) return header->file_groups[i]; } return NULL; } const char* unshield_file_group_name(Unshield* unshield, int index)/*{{{*/ { Header* header = unshield->header_list; if (index >= 0 && index < header->file_group_count) return header->file_groups[index]->name; else return NULL; }/*}}}*/ unshield-1.4.2/lib/helper.c000066400000000000000000000127251303674433700155430ustar00rootroot00000000000000#define _BSD_SOURCE 1 #define _DEFAULT_SOURCE 1 #include "internal.h" #include "log.h" #include "convert_utf/ConvertUTF.h" #include #include #include #include #include #include #ifdef _WIN32 #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) #include #ifndef PATH_MAX #define PATH_MAX _MAX_PATH #endif #else #include #endif #define VERBOSE 0 FILE* unshield_fopen_for_reading(Unshield* unshield, int index, const char* suffix) { if (unshield && unshield->filename_pattern) { FILE* result = NULL; char* filename = NULL; char* dirname = NULL; char * p = strrchr(unshield->filename_pattern, '/'); const char *q; struct dirent *dent = NULL; DIR *sourcedir = NULL; long int path_max; #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf(unshield->filename_pattern, _PC_PATH_MAX); if (path_max <= 0) path_max = 4096; #endif dirname = malloc(path_max); filename = malloc(path_max); if (filename == NULL || dirname == NULL) { unshield_error("Unable to allocate memory.\n"); goto exit; } if(snprintf(filename, path_max, unshield->filename_pattern, index, suffix)>=path_max) { unshield_error("Pathname exceeds system limits.\n"); goto exit; } q=strrchr(filename,'/'); if (q) q++; else q=filename; if (p) { strncpy( dirname, unshield->filename_pattern,path_max); if ((unsigned int)(p-unshield->filename_pattern) > path_max) { unshield_trace("WARN: size\n"); dirname[path_max-1]=0; } else dirname[(p-unshield->filename_pattern)] = 0; } else strcpy(dirname,"."); sourcedir = opendir(dirname); /* Search for the File case independent */ if (sourcedir) { for (dent=readdir(sourcedir);dent;dent=readdir(sourcedir)) { if (!(strcasecmp(q, dent->d_name))) { /*unshield_trace("Found match %s\n",dent->d_name);*/ break; } } if (dent == NULL) { unshield_trace("File %s not found even case insensitive\n",filename); goto exit; } else if(snprintf(filename, path_max, "%s/%s", dirname, dent->d_name)>=path_max) { unshield_error("Pathname exceeds system limits.\n"); goto exit; } } else unshield_trace("Could not open directory %s error %s\n", dirname, strerror(errno)); #if VERBOSE unshield_trace("Opening file '%s'", filename); #endif result = fopen(filename, "rb"); exit: if (sourcedir) closedir(sourcedir); free(filename); free(dirname); return result; } return NULL; } long unshield_fsize(FILE* file) { long result; long previous = ftell(file); fseek(file, 0L, SEEK_END); result = ftell(file); fseek(file, previous, SEEK_SET); return result; } bool unshield_read_common_header(uint8_t** buffer, CommonHeader* common) { uint8_t* p = *buffer; common->signature = READ_UINT32(p); p += 4; if (CAB_SIGNATURE != common->signature) { unshield_error("Invalid file signature"); if (MSCF_SIGNATURE == common->signature) unshield_warning("Found Microsoft Cabinet header. Use cabextract (http://www.kyz.uklinux.net/cabextract.php) to unpack this file."); return false; } common->version = READ_UINT32(p); p += 4; common->volume_info = READ_UINT32(p); p += 4; common->cab_descriptor_offset = READ_UINT32(p); p += 4; common->cab_descriptor_size = READ_UINT32(p); p += 4; #if VERBOSE unshield_trace("Common header: %08x %08x %08x %08x", common->version, common->volume_info, common->cab_descriptor_offset, common->cab_descriptor_size); #endif *buffer = p; return true; } /** Get pointer at cab descriptor + offset */ uint8_t* unshield_header_get_buffer(Header* header, uint32_t offset) { if (offset) return header->data + header->common.cab_descriptor_offset + offset; else return NULL; } static int unshield_strlen_utf16(const uint16_t* utf16) { const uint16_t* current = utf16; while (*current++) ; return current - utf16; } static StringBuffer* unshield_add_string_buffer(Header* header) { StringBuffer* result = NEW1(StringBuffer); result->next = header->string_buffer; return header->string_buffer = result; } static const char* unshield_utf16_to_utf8(Header* header, const uint16_t* utf16) { StringBuffer* string_buffer = unshield_add_string_buffer(header); int length = unshield_strlen_utf16(utf16); int buffer_size = 2 * length + 1; char* target = string_buffer->string = NEW(char, buffer_size); ConversionResult result = ConvertUTF16toUTF8( (const UTF16**)&utf16, utf16 + length + 1, (UTF8**)&target, (UTF8*)(target + buffer_size), lenientConversion); if (result != conversionOK) { /* fail fast */ abort(); } return string_buffer->string; } const char* unshield_get_utf8_string(Header* header, const void* buffer) { if (header->major_version >= 17 && buffer != NULL) { return unshield_utf16_to_utf8(header, (const uint16_t*)buffer); } else { return (const char*)buffer; } } /** Get string at cab descriptor offset + string offset */ const char* unshield_header_get_string(Header* header, uint32_t offset) { return unshield_get_utf8_string(header, unshield_header_get_buffer(header, offset)); } unshield-1.4.2/lib/internal.h000066400000000000000000000060251303674433700161010ustar00rootroot00000000000000/* $Id$ */ #ifndef __internal_h__ #define __internal_h__ #include "libunshield.h" #include "lib/unshield_config.h" #if HAVE_STDINT_H #include #elif HAVE_INTTYPES_H #include #endif #include #include /* for FILE */ #include "cabfile.h" typedef struct _StringBuffer StringBuffer; struct _StringBuffer { StringBuffer* next; char* string; }; typedef struct _Header Header; struct _Header { Header* next; int index; uint8_t* data; size_t size; int major_version; /* shortcuts */ CommonHeader common; CabDescriptor cab; uint32_t* file_table; FileDescriptor** file_descriptors; int component_count; UnshieldComponent** components; int file_group_count; UnshieldFileGroup** file_groups; StringBuffer* string_buffer; }; struct _Unshield { Header* header_list; char* filename_pattern; }; /* Internal component functions */ UnshieldComponent* unshield_component_new(Header* header, uint32_t offset); void unshield_component_destroy(UnshieldComponent* self); /* Internal file group functions */ UnshieldFileGroup* unshield_file_group_new(Header* header, uint32_t offset); void unshield_file_group_destroy(UnshieldFileGroup* self); /* Helpers */ FILE* unshield_fopen_for_reading(Unshield* unshield, int index, const char* suffix); long unshield_fsize(FILE* file); bool unshield_read_common_header(uint8_t** buffer, CommonHeader* common); const char* unshield_get_utf8_string(Header* header, const void* buffer); const char* unshield_header_get_string(Header* header, uint32_t offset); uint8_t* unshield_header_get_buffer(Header* header, uint32_t offset); /* Constants */ #define HEADER_SUFFIX "hdr" #define CABINET_SUFFIX "cab" /* Macros for safer development */ #define FREE(ptr) { if (ptr) { free(ptr); ptr = NULL; } } #define STRDUP(str) ((str) ? strdup(str) : NULL) #define NEW(type, count) ((type*)calloc(count, sizeof(type))) #define NEW1(type) ((type*)calloc(1, sizeof(type))) #define FCLOSE(file) if (file) { fclose(file); file = NULL; } #define FSIZE(file) (file ? unshield_fsize(file) : 0) #define STREQ(s1,s2) (0 == strcmp(s1,s2)) #if WORDS_BIGENDIAN #if HAVE_BYTESWAP_H #include #elif HAVE_SYS_BYTESWAP_H #include #else /* use our own functions */ #define IMPLEMENT_BSWAP_XX 1 #define bswap_16 unshield_bswap_16 #define bswap_32 unshield_bswap_32 uint16_t bswap_16(uint16_t x); uint32_t bswap_32(uint32_t x); #endif #define letoh16(x) bswap_16(x) #define letoh32(x) bswap_32(x) #else #define letoh32(x) (x) #define letoh16(x) (x) #endif static inline uint16_t get_unaligned_le16(const uint8_t *p) { return p[0] | p[1] << 8; } static inline uint32_t get_unaligned_le32(const uint8_t *p) { return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; } #define READ_UINT16(p) get_unaligned_le16(p) #define READ_UINT32(p) get_unaligned_le32(p) #define READ_INT16(p) ((int16_t)READ_UINT16(p)) #define READ_INT32(p) ((int32_t)READ_UINT32(p)) #endif unshield-1.4.2/lib/libunshield.c000066400000000000000000000243751303674433700165720ustar00rootroot00000000000000/* $Id$ */ #define _BSD_SOURCE 1 #define _DEFAULT_SOURCE 1 #include "internal.h" #include "log.h" #include #include #include #include /** Create filename pattern used by unshield_fopen_for_reading() */ static bool unshield_create_filename_pattern(Unshield* unshield, const char* filename)/*{{{*/ { /* TODO Correct his function so that it handles filenames with more than one dot ('.')! */ if (unshield && filename) { char pattern[256]; char* prefix = strdup(filename); char* p = strrchr(prefix, '/'); if (!p) p = prefix; for (; *p != '\0'; p++) { if ('.' == *p || isdigit(*p)) { *p = '\0'; break; } } snprintf(pattern, sizeof(pattern), "%s%%i.%%s", prefix); free(prefix); FREE(unshield->filename_pattern); unshield->filename_pattern = strdup(pattern); return true; } else return false; }/*}}}*/ static bool unshield_get_common_header(Header* header) { uint8_t* p = header->data; return unshield_read_common_header(&p, &header->common); } static bool unshield_get_cab_descriptor(Header* header) { if (header->common.cab_descriptor_size) { uint8_t* p = header->data + header->common.cab_descriptor_offset; int i; p += 0xc; header->cab.file_table_offset = READ_UINT32(p); p += 4; p += 4; header->cab.file_table_size = READ_UINT32(p); p += 4; header->cab.file_table_size2 = READ_UINT32(p); p += 4; header->cab.directory_count = READ_UINT32(p); p += 4; p += 8; header->cab.file_count = READ_UINT32(p); p += 4; header->cab.file_table_offset2 = READ_UINT32(p); p += 4; assert((p - (header->data + header->common.cab_descriptor_offset)) == 0x30); if (header->cab.file_table_size != header->cab.file_table_size2) unshield_warning("File table sizes do not match"); unshield_trace("Cabinet descriptor: %08x %08x %08x %08x", header->cab.file_table_offset, header->cab.file_table_size, header->cab.file_table_size2, header->cab.file_table_offset2 ); unshield_trace("Directory count: %i", header->cab.directory_count); unshield_trace("File count: %i", header->cab.file_count); p += 0xe; for (i = 0; i < MAX_FILE_GROUP_COUNT; i++) { header->cab.file_group_offsets[i] = READ_UINT32(p); p += 4; } for (i = 0; i < MAX_COMPONENT_COUNT; i++) { header->cab.component_offsets[i] = READ_UINT32(p); p += 4; } return true; } else { unshield_error("No CAB descriptor available!"); return false; } } static bool unshield_get_file_table(Header* header) { uint8_t* p = header->data + header->common.cab_descriptor_offset + header->cab.file_table_offset; int count = header->cab.directory_count + header->cab.file_count; int i; header->file_table = calloc(count, sizeof(uint32_t)); for (i = 0; i < count; i++) { header->file_table[i] = READ_UINT32(p); p += 4; } return true; } static bool unshield_header_get_components(Header* header)/*{{{*/ { int count = 0; int i; int available = 16; header->components = malloc(available * sizeof(UnshieldComponent*)); for (i = 0; i < MAX_COMPONENT_COUNT; i++) { if (header->cab.component_offsets[i]) { OffsetList list; list.next_offset = header->cab.component_offsets[i]; while (list.next_offset) { uint8_t* p = unshield_header_get_buffer(header, list.next_offset); list.name_offset = READ_UINT32(p); p += 4; list.descriptor_offset = READ_UINT32(p); p += 4; list.next_offset = READ_UINT32(p); p += 4; if (count == available) { available <<= 1; header->components = realloc(header->components, available * sizeof(UnshieldComponent*)); } header->components[count++] = unshield_component_new(header, list.descriptor_offset); } } } header->component_count = count; return true; } /*}}}*/ static bool unshield_header_get_file_groups(Header* header)/*{{{*/ { int count = 0; int i; int available = 16; header->file_groups = malloc(available * sizeof(UnshieldFileGroup*)); for (i = 0; i < MAX_FILE_GROUP_COUNT; i++) { if (header->cab.file_group_offsets[i]) { OffsetList list; list.next_offset = header->cab.file_group_offsets[i]; while (list.next_offset) { uint8_t* p = unshield_header_get_buffer(header, list.next_offset); list.name_offset = READ_UINT32(p); p += 4; list.descriptor_offset = READ_UINT32(p); p += 4; list.next_offset = READ_UINT32(p); p += 4; if (count == available) { available <<= 1; header->file_groups = realloc(header->file_groups, available * sizeof(UnshieldFileGroup*)); } header->file_groups[count++] = unshield_file_group_new(header, list.descriptor_offset); } } } header->file_group_count = count; return true; } /*}}}*/ /** Read all header files */ static bool unshield_read_headers(Unshield* unshield, int version)/*{{{*/ { int i; bool iterate = true; Header* previous = NULL; if (unshield->header_list) { unshield_warning("Already have a header list"); return true; } for (i = 1; iterate; i++) { FILE* file = unshield_fopen_for_reading(unshield, i, HEADER_SUFFIX); if (file) { unshield_trace("Reading header from .hdr file %i.", i); iterate = false; } else { unshield_trace("Could not open .hdr file %i. Reading header from .cab file %i instead.", i, i); file = unshield_fopen_for_reading(unshield, i, CABINET_SUFFIX); } if (file) { size_t bytes_read; Header* header = NEW1(Header); header->index = i; header->size = FSIZE(file); if (header->size < 4) { unshield_error("Header file %i too small", i); goto error; } header->data = malloc(header->size); if (!header->data) { unshield_error("Failed to allocate memory for header file %i", i); goto error; } bytes_read = fread(header->data, 1, header->size, file); FCLOSE(file); if (bytes_read != header->size) { unshield_error("Failed to read from header file %i. Expected = %i, read = %i", i, header->size, bytes_read); goto error; } if (!unshield_get_common_header(header)) { unshield_error("Failed to read common header from header file %i", i); goto error; } if (version != -1) { header->major_version = version; } else if (header->common.version >> 24 == 1) { header->major_version = (header->common.version >> 12) & 0xf; } else if (header->common.version >> 24 == 2 || header->common.version >> 24 == 4) { header->major_version = (header->common.version & 0xffff); if (header->major_version != 0) header->major_version = header->major_version / 100; } #if 0 if (header->major_version < 5) header->major_version = 5; #endif unshield_trace("Version 0x%08x handled as major version %i", header->common.version, header->major_version); if (!unshield_get_cab_descriptor(header)) { unshield_error("Failed to read CAB descriptor from header file %i", i); goto error; } if (!unshield_get_file_table(header)) { unshield_error("Failed to read file table from header file %i", i); goto error; } if (!unshield_header_get_components(header)) { unshield_error("Failed to read components from header file %i", i); goto error; } if (!unshield_header_get_file_groups(header)) { unshield_error("Failed to read file groups from header file %i", i); goto error; } if (previous) previous->next = header; else previous = unshield->header_list = header; continue; error: if (header) FREE(header->data); FREE(header); iterate = false; } else iterate = false; } return (unshield->header_list != NULL); }/*}}}*/ Unshield* unshield_open(const char* filename)/*{{{*/ { return unshield_open_force_version(filename, -1); }/*}}}*/ Unshield* unshield_open_force_version(const char* filename, int version)/*{{{*/ { Unshield* unshield = NEW1(Unshield); if (!unshield) { unshield_error("Failed to allocate memory for Unshield structure"); goto error; } if (!unshield_create_filename_pattern(unshield, filename)) { unshield_error("Failed to create filename pattern"); goto error; } if (!unshield_read_headers(unshield, version)) { unshield_error("Failed to read header files"); goto error; } return unshield; error: unshield_close(unshield); return NULL; }/*}}}*/ static void unshield_free_string_buffers(Header* header) { StringBuffer* current = header->string_buffer; header->string_buffer = NULL; while (current != NULL) { StringBuffer* next = current->next; FREE(current->string); FREE(current); current = next; } } void unshield_close(Unshield* unshield)/*{{{*/ { if (unshield) { Header* header; for(header = unshield->header_list; header; ) { Header* next = header->next; int i; unshield_free_string_buffers(header); if (header->components) { for (i = 0; i < header->component_count; i++) unshield_component_destroy(header->components[i]); free(header->components); } if (header->file_groups) { for (i = 0; i < header->file_group_count; i++) unshield_file_group_destroy(header->file_groups[i]); free(header->file_groups); } if (header->file_descriptors) { for (i = 0; i < (int)header->cab.file_count; i++) FREE(header->file_descriptors[i]); free(header->file_descriptors); } FREE(header->file_table); FREE(header->data); FREE(header); header = next; } FREE(unshield->filename_pattern); free(unshield); } }/*}}}*/ bool unshield_is_unicode(Unshield* unshield) { if (unshield) { Header* header = unshield->header_list; return header->major_version >= 17; } else return false; } unshield-1.4.2/lib/libunshield.h000066400000000000000000000047341303674433700165740ustar00rootroot00000000000000/* $Id$ */ #ifndef __unshield_h__ #define __unshield_h__ #include #include #define UNSHIELD_LOG_LEVEL_LOWEST 0 #define UNSHIELD_LOG_LEVEL_ERROR 1 #define UNSHIELD_LOG_LEVEL_WARNING 2 #define UNSHIELD_LOG_LEVEL_TRACE 3 #define UNSHIELD_LOG_LEVEL_HIGHEST 4 #ifdef __cplusplus extern "C" { #endif typedef struct _Unshield Unshield; /* Logging */ void unshield_set_log_level(int level); /* Open/close functions */ Unshield* unshield_open(const char* filename); Unshield* unshield_open_force_version(const char* filename, int version); void unshield_close(Unshield* unshield); /* Component functions */ typedef struct { const char* name; unsigned file_group_count; const char** file_group_names; } UnshieldComponent; int unshield_component_count (Unshield* unshield); const char* unshield_component_name (Unshield* unshield, int index); /* File group functions */ typedef struct { const char* name; unsigned first_file; unsigned last_file; } UnshieldFileGroup; int unshield_file_group_count (Unshield* unshield); UnshieldFileGroup* unshield_file_group_get (Unshield* unshield, int index); UnshieldFileGroup* unshield_file_group_find (Unshield* unshield, const char* name); const char* unshield_file_group_name (Unshield* unshield, int index); /* Directory functions */ int unshield_directory_count (Unshield* unshield); const char* unshield_directory_name (Unshield* unshield, int index); /* File functions */ int unshield_file_count (Unshield* unshield); const char* unshield_file_name (Unshield* unshield, int index); bool unshield_file_is_valid (Unshield* unshield, int index); bool unshield_file_save (Unshield* unshield, int index, const char* filename); int unshield_file_directory (Unshield* unshield, int index); size_t unshield_file_size (Unshield* unshield, int index); /** For investigation of compressed data */ bool unshield_file_save_raw(Unshield* unshield, int index, const char* filename); /** Maybe it's just gzip without size? */ 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 #endif unshield-1.4.2/lib/log.c000066400000000000000000000007701303674433700150420ustar00rootroot00000000000000/* $Id */ #include "log.h" #include #include /* evil static data */ static int current_log_level = UNSHIELD_LOG_LEVEL_HIGHEST; void unshield_set_log_level(int level) { current_log_level = level; } void _unshield_log(int level, const char* file, int line, const char* format, ...) { va_list ap; if (level > current_log_level) return; fprintf(stderr, "[%s:%i] ", file, line); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); fprintf(stderr, "\n"); } unshield-1.4.2/lib/log.h000066400000000000000000000017011303674433700150420ustar00rootroot00000000000000/* $Id$ */ #ifndef __log_h__ #define __log_h__ #include "internal.h" #define UNSHIELD_LOG_LEVEL_LOWEST 0 #define UNSHIELD_LOG_LEVEL_ERROR 1 #define UNSHIELD_LOG_LEVEL_WARNING 2 #define UNSHIELD_LOG_LEVEL_TRACE 3 #define UNSHIELD_LOG_LEVEL_HIGHEST 4 #ifdef __cplusplus extern "C" { #endif void _unshield_log(int level, const char* file, int line, const char* format, ...); #define unshield_trace(format, args...) \ _unshield_log(UNSHIELD_LOG_LEVEL_TRACE,__FUNCTION__, __LINE__, format, ##args) #define unshield_warning(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,__FUNCTION__, __LINE__, format, ##args) #define unshield_error(format, args...) \ _unshield_log(UNSHIELD_LOG_LEVEL_ERROR,__FUNCTION__, __LINE__, format, ##args) #ifdef __cplusplus } #endif #endif unshield-1.4.2/lib/md5/000077500000000000000000000000001303674433700145765ustar00rootroot00000000000000unshield-1.4.2/lib/md5/CMakeLists.txt000066400000000000000000000002331303674433700173340ustar00rootroot00000000000000set(LIBMD5_UTF_HEADES "global.h" "md5.h" ) set(LIBMD5_UTF_SOURCES "md5c.c" ) add_library(md5 STATIC ${LIBMD5_UTF_HEADES} ${LIBMD5_UTF_SOURCES}) unshield-1.4.2/lib/md5/global.h000066400000000000000000000014101303674433700162030ustar00rootroot00000000000000/* GLOBAL.H - RSAREF types and constants */ /* PROTOTYPES should be set to one if and only if the compiler supports function argument prototyping. The following makes PROTOTYPES default to 0 if it has not already been defined with C compiler flags. */ #ifndef PROTOTYPES #define PROTOTYPES 0 #endif /* POINTER defines a generic pointer type */ typedef unsigned char *POINTER; /* UINT2 defines a two byte word */ typedef unsigned short int UINT2; /* UINT4 defines a four byte word */ typedef unsigned int UINT4; /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it returns an empty list. */ #if PROTOTYPES #define PROTO_LIST(list) list #else #define PROTO_LIST(list) () #endif unshield-1.4.2/lib/md5/md5.h000066400000000000000000000025061303674433700154370ustar00rootroot00000000000000/* MD5.H - header file for MD5C.C */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ /* MD5 context. */ typedef struct { UINT4 state[4]; /* state (ABCD) */ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } MD5_CTX; void MD5Init PROTO_LIST ((MD5_CTX *)); void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int)); void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); unshield-1.4.2/lib/md5/md5c.c000066400000000000000000000243071303674433700156000ustar00rootroot00000000000000/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #include "global.h" #include "md5.h" /* Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); static void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int)); static void Decode PROTO_LIST ((UINT4 *, unsigned char *, unsigned int)); static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) ((((x) << (n)) & 0xffffffffU) | ((x) >> (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) { \ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } /* MD5 initialization. Begins an MD5 operation, writing a new context. */ void MD5Init (context) MD5_CTX *context; /* context */ { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */ void MD5Update (context, input, inputLen) MD5_CTX *context; /* context */ unsigned char *input; /* input block */ unsigned int inputLen; /* length of input block */ { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int)((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) context->count[1]++; context->count[1] += ((UINT4)inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform (context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform (context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ void MD5Final (digest, context) unsigned char digest[16]; /* message digest */ MD5_CTX *context; /* context */ { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode (bits, context->count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int)((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); MD5Update (context, PADDING, padLen); /* Append length (before padding) */ MD5Update (context, bits, 8); /* Store state in digest */ Encode (digest, context->state, 16); /* Zeroize sensitive information. */ MD5_memset ((POINTER)context, 0, sizeof (*context)); } /* MD5 basic transformation. Transforms state based on block. */ static void MD5Transform (state, block) UINT4 state[4]; unsigned char block[64]; { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode (x, block, 64); /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ MD5_memset ((POINTER)x, 0, sizeof (x)); } /* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */ static void Encode (output, input, len) unsigned char *output; UINT4 *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ static void Decode (output, input, len) UINT4 *output; unsigned char *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); } /* Note: Replace "for loop" with standard memcpy if possible. */ static void MD5_memcpy (output, input, len) POINTER output; POINTER input; unsigned int len; { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. */ static void MD5_memset (output, value, len) POINTER output; int value; unsigned int len; { unsigned int i; for (i = 0; i < len; i++) ((char *)output)[i] = (char)value; } unshield-1.4.2/lib/unshield_config.h.in000066400000000000000000000044301303674433700200300ustar00rootroot00000000000000/* Define to 1 if you have the header file. */ #cmakedefine HAVE_BYTESWAP_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDBOOL_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_BYTESWAP_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 /* Name of package */ #define PACKAGE "@PROJECT_NAME@" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ #define PACKAGE_NAME "@PROJECT_NAME@" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "@PROJECT_NAME@ @PROJECT_VERSION@" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "@PROJECT_NAME@" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "@PROJECT_VERSION@" /* printf format that works with size_t values */ #cmakedefine SIZE_FORMAT "@SIZE_FORMAT@" /* 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 /* Version number of package */ #define VERSION "@PROJECT_VERSION@" /* Enable GNU style printf formatters */ #define __USE_MINGW_ANSI_STDIO 1 unshield-1.4.2/libunshield.pc.in000066400000000000000000000004771303674433700166060ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_FULL_BINDIR@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: libunshield Description: Library to extract CAB files from InstallShield installers Version: @PROJECT_VERSION@ Libs: -L${libdir} -lunshield Cflags: -I${includedir} unshield-1.4.2/man/000077500000000000000000000000001303674433700141165ustar00rootroot00000000000000unshield-1.4.2/man/unshield.1000066400000000000000000000027421303674433700160200ustar00rootroot00000000000000.TH UNSHIELD "1" "July 2004" "The SynCE project" "http://www.synce.org" .SH NAME unshield \- extract CAB files from an InstallShield installer archive .SH SYNOPSIS unshield [\-c COMPONENT] [\-d DIRECTORY] [\-D LEVEL] [\-g GROUP] [\-h] [\-j] [\-L] [\-n] [\-o] [\-O] [\-r] [\-v] [\-V] c|g|l|t|x CABFILE .SH DESCRIPTION Unshield extracts CAB files from InstallShield installers, used to install software on Microsoft Windows based machines. .SH OPTIONS .TP \fB\-c\fR COMPONENT Only list/extract this component .TP \fB\-d\fR DIRECTORY Extract files to DIRECTORY .TP \fB\-D\fR LEVEL Set debug log level 0 \- No logging (default) 1 \- Errors only 2 \- Errors and warnings 3 \- Errors, warnings and debug messages .TP \fB\-g\fR GROUP Only list/extract this file group .TP \fB\-h\fR Show help message .TP \fB\-j\fR Junk paths (do not make directories) .TP \fB\-L\fR Make file and directory names lowercase .TP \fB\-n\fR Never overwrite files .TP \fB\-o\fR Always overwrite files .TP \fB\-O\fR Use old compression .TP \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 \fB\-V\fR Print version information .SS "Commands:" .TP c List components .TP g List file groups .TP l List files .TP t Test files .TP x Extract files .SS "Other:" .TP CABFILE The InstallShield installer file to act upon .SH "AUTHOR" This manual page was adapted by Mark Ellis , from the skeleton generated by help2man unshield-1.4.2/rebuild.sh000077500000000000000000000002641303674433700153320ustar00rootroot00000000000000#!/bin/sh set -e set -x export CFLAGS="-Wall -Werror -ggdb3" cd `dirname $0` mkdir -p build cd build cmake -DCMAKE_INSTALL_PREFIX:PATH=/var/tmp/unshield .. && make && make install unshield-1.4.2/run-tests.sh000077500000000000000000000004371303674433700156520ustar00rootroot00000000000000#!/bin/bash ALL_RET=0 for SCRIPT in $(find $(dirname $0)/test/v* -name '*.sh'); do echo -n "Running test $SCRIPT..." bash ${SCRIPT} TEST_RET=$? if [ "$TEST_RET" = "0" ]; then echo "succeeded" else echo "FAILED with code $TEST_RET" ALL_RET=1 fi done exit $ALL_RET unshield-1.4.2/src/000077500000000000000000000000001303674433700141325ustar00rootroot00000000000000unshield-1.4.2/src/CMakeLists.txt000066400000000000000000000011321303674433700166670ustar00rootroot00000000000000LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) IF("${isSystemDir}" STREQUAL "-1") SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") ENDIF("${isSystemDir}" STREQUAL "-1") add_executable(unshield "unshield.c") target_link_libraries(unshield libunshield) add_executable(unshield-deobfuscate "unshield-deobfuscate.c") target_link_libraries(unshield-deobfuscate libunshield) install(TARGETS unshield RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})unshield-1.4.2/src/unshield-deobfuscate.c000066400000000000000000000017721303674433700204020ustar00rootroot00000000000000#include #include #include "../lib/libunshield.h" int main(int argc, char** argv) { unsigned seed = 0; FILE* input = NULL; FILE* output = NULL; size_t size; unsigned char buffer[16384]; if (argc != 3) { fprintf(stderr, "Syntax:\n" " %s INPUT-FILE OUTPUT-FILE\n", argv[0]); exit(1); } input = fopen(argv[1], "rb"); if (!input) { fprintf(stderr, "Failed to open %s for reading\n", argv[1]); exit(2); } output = fopen(argv[2], "wb"); if (!output) { fprintf(stderr, "Failed to open %s for writing\n", argv[2]); exit(3); } while ((size = fread(buffer, 1, sizeof(buffer), input)) != 0) { unshield_deobfuscate(buffer, size, &seed); if (fwrite(buffer, 1, size, output) != size) { fprintf(stderr, "Failed to write %lu bytes to %s\n", (unsigned long)size, argv[2]); exit(4); } } fclose(input); fclose(output); return 0; } unshield-1.4.2/src/unshield.c000066400000000000000000000435061303674433700161210ustar00rootroot00000000000000/* $Id$ */ #ifdef __linux__ #define _BSD_SOURCE 1 #define _DEFAULT_SOURCE 1 #define _POSIX_C_SOURCE 2 #endif #include #include #include #include #include #include #include #include #include "../lib/libunshield.h" #ifdef HAVE_CONFIG_H #include "lib/unshield_config.h" #endif #if HAVE_FNMATCH #include #endif #ifdef HAVE_ICONV #include #include #endif #ifndef VERSION #define VERSION "Unknown" #endif #define FREE(ptr) { if (ptr) { free(ptr); ptr = NULL; } } #ifdef _WIN32 #define realpath(N,R) _fullpath((R),(N),_MAX_PATH) #include #ifndef PATH_MAX #define PATH_MAX _MAX_PATH #endif #else #include #endif #ifndef NAME_MAX #define NAME_MAX FILENAME_MAX #endif typedef enum { OVERWRITE_ASK, OVERWRITE_NEVER, OVERWRITE_ALWAYS, } OVERWRITE; typedef enum { ACTION_EXTRACT, ACTION_LIST_COMPONENTS, ACTION_LIST_FILE_GROUPS, ACTION_LIST_FILES, ACTION_TEST } ACTION; typedef enum { FORMAT_NEW, FORMAT_OLD, FORMAT_RAW } FORMAT; #define DEFAULT_OUTPUT_DIRECTORY "." static const char* output_directory = DEFAULT_OUTPUT_DIRECTORY; 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; static int log_level = UNSHIELD_LOG_LEVEL_LOWEST; static int exit_status = 0; static FORMAT format = FORMAT_NEW; 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)/*{{{*/ { struct stat dir_stat; const char* p = directory; bool success = false; char* current = NULL; while (p && *p) { if ('/' == *p) p++; else if (0 == strncmp(p, "./", 2)) p+=2; else if (0 == strncmp(p, "../", 3)) p+=3; else { const char* slash = strchr(p, '/'); current = strdup(directory); if (slash) current[slash-directory] = '\0'; if (stat(current, &dir_stat) < 0) { #ifdef __MINGW32__ if (_mkdir(current) < 0) #else if (mkdir(current, 0700) < 0) #endif { fprintf(stderr, "Failed to create directory %s\n", directory); if(strlen(directory)>NAME_MAX) fprintf(stderr, "Directory name must be less than %i characters\n", NAME_MAX+1); goto exit; } } p = slash; FREE(current); } } success = true; exit: FREE(current); 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] [-e ENCODING] [-GhlOrV] c|g|l|t|x CABFILE [FILENAME...]\n" "\n" "Options:\n" "\t-c COMPONENT Only list/extract this component\n" "\t-d DIRECTORY Extract files to DIRECTORY\n" "\t-D LEVEL Set debug log level\n" "\t 0 - No logging (default)\n" "\t 1 - Errors only\n" "\t 2 - Errors and warnings\n" "\t 3 - Errors, warnings and debug messages\n" "\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" "\tc List components\n" "\tg List file groups\n" "\tl List files\n" "\tt Test files\n" "\tx Extract files\n" "\n" "Other:\n" "\tCABFILE The file to list or extract contents of\n" "\tFILENAME... Optionally specify names of specific files to extract" #if HAVE_FNMATCH " (wildcards are supported)" #endif "\n" , name); #if 0 "\t-n Never overwrite files\n" "\t-o Overwrite files WITHOUT prompting\n" "\t-v Verbose output\n" #endif } static bool handle_parameters( int argc, char* const argv[]) { int c; while ((c = getopt(argc, argv, "c:d:D:g:hi:e:jLnoOrRV")) != -1) { switch (c) { case 'c': component_name = optarg; break; case 'd': output_directory = optarg; break; case 'D': log_level = atoi(optarg); break; case 'g': file_group_name = optarg; break; case 'i': 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; case 'L': make_lowercase = true; break; case 'R': raw_filename = true; break; case 'n': overwrite = OVERWRITE_NEVER; break; case 'o': overwrite = OVERWRITE_ALWAYS; break; case 'O': format = FORMAT_OLD; break; case 'r': format = FORMAT_RAW; break; case 'v': verbose = true; break; case 'V': printf("Unshield version " VERSION ". Copyright (C) 2003-2013 David Eriksson.\n"); exit(0); break; case 'h': default: show_usage(argv[0]); return false; } } unshield_set_log_level(log_level); if (optind == argc || !argv[optind]) { fprintf(stderr, "No action provided on command line.\n\n"); show_usage(argv[0]); return false; } char action_char = argv[optind++][0]; switch (action_char) { case 'c': action = ACTION_LIST_COMPONENTS; break; case 'g': action = ACTION_LIST_FILE_GROUPS; break; case 'l': action = ACTION_LIST_FILES; break; case 't': action = ACTION_TEST; break; case 'x': action = ACTION_EXTRACT; break; default: fprintf(stderr, "Unknown action '%c' on command line.\n\n", action_char); show_usage(argv[0]); return false; } cab_file_name = argv[optind++]; if (cab_file_name == NULL) { fprintf(stderr, "No InstallShield Cabinet File name provided on command line.\n\n"); show_usage(argv[0]); return false; } path_name_count = argc - optind; path_names = &argv[optind]; return true; } static bool extract_file(Unshield* unshield, const char* prefix, int index) { bool success; char* dirname; char* filename; 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(prefix, _PC_PATH_MAX); if (path_max <= 0) path_max = 4096; #endif real_output_directory = malloc(path_max); real_filename = malloc(path_max); dirname = malloc(path_max); filename = malloc(path_max); if (real_output_directory == NULL || real_filename == NULL) { fprintf(stderr,"Unable to allocate memory."); success=false; goto exit; } if(strlen(output_directory) < path_max-1) { strncpy(dirname, output_directory,path_max-1); if (path_max > 0) dirname[path_max - 1]= '\0'; strcat(dirname, "/"); } else { fprintf(stderr, "\nOutput directory exceeds maximum path length.\n"); success = false; goto exit; } if (prefix && prefix[0]) { if(strlen(dirname)+strlen(prefix) < path_max-1) { strcat(dirname, prefix); strcat(dirname, "/"); } else { fprintf(stderr, "\nOutput directory exceeds maximum path length.\n"); success = false; goto exit; } } if (!junk_paths && directory >= 0) { const char* tmp = unshield_directory_name(unshield, directory); if (tmp && tmp[0]) { if(strlen(dirname)+strlen(tmp) < path_max-1) { strcat(dirname, tmp); strcat(dirname, "/"); } else { fprintf(stderr, "\nOutput directory exceeds maximum path length.\n"); success = false; goto exit; } } } for (p = dirname + strlen(output_directory); *p != '\0'; p++) { switch (*p) { case '\\': *p = '/'; break; case ' ': case '<': case '>': case '[': case ']': *p = '_'; break; default: 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, "/"); #endif make_sure_directory_exists(dirname); snprintf(filename, path_max, "%s%s", dirname, unshield_file_name(unshield, index)); for (p = filename + strlen(dirname); *p != '\0'; 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); success = false; goto exit; } printf(" extracting: %s\n", filename); switch (format) { case FORMAT_NEW: success = unshield_file_save(unshield, index, filename); break; case FORMAT_OLD: success = unshield_file_save_old(unshield, index, filename); break; case FORMAT_RAW: success = unshield_file_save_raw(unshield, index, filename); break; } exit: if (!success) { fprintf(stderr, "Failed to extract file '%s'.%s\n", unshield_file_name(unshield, index), (log_level < 3) ? "Run unshield again with -D 3 for more information." : ""); unlink(filename); exit_status = 1; } free(real_filename); free(real_output_directory); free(dirname); free(filename); return success; } static bool should_process_file(Unshield* unshield, int index) { int i; if (path_name_count == 0) return true; for (i = 0; i < path_name_count; i++) { #if HAVE_FNMATCH if (fnmatch(path_names[i], unshield_file_name(unshield, index), 0) == 0) return true; #else if (strcmp(path_names[i], unshield_file_name(unshield, index)) == 0) return true; #endif } return false; } static int extract_helper(Unshield* unshield, const char* prefix, int first, int last)/*{{{*/ { int i; int count = 0; for (i = first; i <= last; i++) { if (unshield_file_is_valid(unshield, i) && should_process_file(unshield, i) && extract_file(unshield, prefix, i)) count++; } return count; }/*}}}*/ static bool test_file(Unshield* unshield, int index) { bool success; printf(" testing: %s\n", unshield_file_name(unshield, index)); success = unshield_file_save(unshield, index, NULL); if (!success) { fprintf(stderr, "Failed to extract file '%s'.%s\n", unshield_file_name(unshield, index), (log_level < 3) ? "Run unshield again with -D 3 for more information." : ""); exit_status = 1; } return success; } static int test_helper(Unshield* unshield, const char* prefix, int first, int last)/*{{{*/ { int i; int count = 0; for (i = first; i <= last; i++) { if (unshield_file_is_valid(unshield, i) && test_file(unshield, i)) count++; } return count; }/*}}}*/ static bool list_components(Unshield* unshield) { int i; int count = unshield_component_count(unshield); if (count < 0) return false; for (i = 0; i < count; i++) { printf("%s\n", unshield_component_name(unshield, i)); } printf("-------\n%i components\n", count); return true; } static bool list_file_groups(Unshield* unshield) { int i; int count = unshield_file_group_count(unshield); if (count < 0) return false; for (i = 0; i < count; i++) { printf("%s\n", unshield_file_group_name(unshield, i)); } printf("-------\n%i file groups\n", count); return true; } static int list_files_helper(Unshield* unshield, const char* prefix, int first, int last)/*{{{*/ { int i; int valid_count = 0; for (i = first; i <= last; i++) { char dirname[4096]; if (unshield_file_is_valid(unshield, i) && should_process_file(unshield, i)) { valid_count++; if (prefix && prefix[0]) { strcpy(dirname, prefix); strcat(dirname, "\\"); } else dirname[0] = '\0'; strcat(dirname, unshield_directory_name(unshield, unshield_file_directory(unshield, i))); #if 0 for (p = dirname + strlen(output_directory); *p != '\0'; p++) if ('\\' == *p) *p = '/'; #endif if (dirname[strlen(dirname)-1] != '\\') strcat(dirname, "\\"); printf(" %8" SIZE_FORMAT " %s%s\n", unshield_file_size(unshield, i), dirname, unshield_file_name(unshield, i)); } } return valid_count; }/*}}}*/ typedef int (*ActionHelper)(Unshield* unshield, const char* prefix, int first, int last); static bool do_action(Unshield* unshield, ActionHelper helper) { int count = 0; if (component_name) { abort(); } else if (file_group_name) { UnshieldFileGroup* file_group = unshield_file_group_find(unshield, file_group_name); printf("File group: %s\n", file_group_name); if (file_group) count = helper(unshield, file_group_name, file_group->first_file, file_group->last_file); } else { int i; for (i = 0; i < unshield_file_group_count(unshield); i++) { UnshieldFileGroup* file_group = unshield_file_group_get(unshield, i); if (file_group) count += helper(unshield, file_group->name, file_group->first_file, file_group->last_file); } } printf(" -------- -------\n %i files\n", count); return true; } int main(int argc, char* const argv[]) { bool success = false; Unshield* unshield = NULL; setlocale(LC_ALL, ""); if (!handle_parameters(argc, argv)) goto exit; unshield = unshield_open_force_version(cab_file_name, is_version); if (!unshield) { fprintf(stderr, "Failed to open %s as an InstallShield Cabinet File\n", cab_file_name); 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) { case ACTION_EXTRACT: success = do_action(unshield, extract_helper); break; case ACTION_LIST_COMPONENTS: success = list_components(unshield); break; case ACTION_LIST_FILE_GROUPS: success = list_file_groups(unshield); break; case ACTION_LIST_FILES: success = do_action(unshield, list_files_helper); break; case ACTION_TEST: if (strcmp(output_directory, DEFAULT_OUTPUT_DIRECTORY) != 0) fprintf(stderr, "Output directory (-d) option has no effect with test (t) command.\n"); if (make_lowercase) fprintf(stderr, "Make lowercase (-L) option has no effect with test (t) command.\n"); success = do_action(unshield, test_helper); break; } 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; } unshield-1.4.2/test/000077500000000000000000000000001303674433700143225ustar00rootroot00000000000000unshield-1.4.2/test/v0/000077500000000000000000000000001303674433700146475ustar00rootroot00000000000000unshield-1.4.2/test/v0/avigomanager.md5000066400000000000000000000055311303674433700177220ustar00rootroot00000000000000a943ad8f40479fa5cd68afba5787be4f ./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 unshield-1.4.2/test/v0/avigomanager.sh000077500000000000000000000020051303674433700176430ustar00rootroot00000000000000#!/bin/bash set -e cd `dirname $0` MD5_FILE=`pwd`/`basename $0 .sh`.md5 UNSHIELD=${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 0unshield-1.4.2/test/v0/the-feeble-files-spanish.md5000066400000000000000000000511331303674433700220240ustar00rootroot00000000000000f77a2f7632408752c29e0beab0ee3d66 ./Essential_Game_Files/0011.VGA d92b95f8b41cadd2daa8fe98b0e66607 ./Essential_Game_Files/0012.VGA 702b790944582ddbb9755b7228e8f147 ./Essential_Game_Files/0021.VGA 95e08584433213bbbe7715d03ed057d5 ./Essential_Game_Files/0022.VGA de4f46b96872f50ed9a9bc86e3f3b74f ./Essential_Game_Files/0071.VGA c9984357a5534e05b9d3f7da36856730 ./Essential_Game_Files/0072.VGA a884cd4b8597f40e9557ef4a7ca80031 ./Essential_Game_Files/0081.VGA e465c315cbe92ba02821c8e9ff927777 ./Essential_Game_Files/0082.VGA a1af4636fe0d3286d17d0aa6ca89fda4 ./Essential_Game_Files/0091.fst 1f8c398703d331547b1b0c33de176eed ./Essential_Game_Files/0091.slw a1af4636fe0d3286d17d0aa6ca89fda4 ./Essential_Game_Files/0091.VGA 34f3dd6e1b6978a0b05ef8b0c33557f4 ./Essential_Game_Files/0092.VGA b089d0826fcd31f4cee07821c421f8b8 ./Essential_Game_Files/0111.VGA 81a2356eaa10b64e96c1df514c613ad7 ./Essential_Game_Files/0112.VGA 1127cc5ca705e233c8d5ce16f6661ab3 ./Essential_Game_Files/0121.VGA e00a8980b4e908bad7649ded80ac90ad ./Essential_Game_Files/0122.VGA dc11c5123a5abf5ec80fd83df3ddf127 ./Essential_Game_Files/0131.VGA 15ab7ba9d8fb87e2f81ded0948718eba ./Essential_Game_Files/0132.VGA 424c1aa5ba80d8fff10c297a7b25a311 ./Essential_Game_Files/0141.VGA 77b7feaee792dd2cb0e0259d0738307d ./Essential_Game_Files/0142.VGA 4e7c1545d3d9380775f6050793a08cae ./Essential_Game_Files/0151.VGA d2591384e041476a671a67a3939ee3ce ./Essential_Game_Files/0152.VGA 3c8b32725559422b302c4bffe97e8ad4 ./Essential_Game_Files/0161.VGA 9c9e47ec2a14b345db3f7bfc9b17fddd ./Essential_Game_Files/0162.VGA f0b876165c7947fce2e3fde53fdc3ffb ./Essential_Game_Files/0163.vga db9f832c74ad1ad8a095de4e5edaf340 ./Essential_Game_Files/0171.VGA 913766b7aee2242cf48d6cee6f16c7f7 ./Essential_Game_Files/0172.VGA a3f245749e396ed70acfcf175b125b45 ./Essential_Game_Files/0181.VGA f9be2faebc1be752d9013e1dd8c8a53c ./Essential_Game_Files/0182.VGA b6454c471d265ae06ad56dfb20c0eff9 ./Essential_Game_Files/0191.VGA 06bd665e453690dbd798cf43f0879b63 ./Essential_Game_Files/0192.VGA f0b876165c7947fce2e3fde53fdc3ffb ./Essential_Game_Files/0193.vga 62d294bc4a70ef39e44c82db15e1dc47 ./Essential_Game_Files/1101.VGA 9e436e2f74476ed57f81bfb46baff8c5 ./Essential_Game_Files/1102.VGA 8c5e9afbdafff2145195262760d8d51d ./Essential_Game_Files/1111.VGA 0cd1408697a4454b0690a92723654546 ./Essential_Game_Files/1112.VGA d6bc66bbf805cfad874dda37d54caf84 ./Essential_Game_Files/1121.VGA b6c6259af57589a6315a516a09dc07a8 ./Essential_Game_Files/1122.VGA 0d30177c9075d5e2d40de5b1a1281a5b ./Essential_Game_Files/1131.VGA d68b6015a7d7bd7c1f755a8af008fc8b ./Essential_Game_Files/1132.VGA a1a36bac72c805ad3b247f5dce4e9f6b ./Essential_Game_Files/1141.VGA b6fd933333588eb55a2b100af503466e ./Essential_Game_Files/1142.VGA cedc3894f34e896da3cd6922412fb60f ./Essential_Game_Files/1151.VGA ee4925c01ba2ee625b54388d61097ffa ./Essential_Game_Files/1152.VGA ac06944d7925d141c01238f6a0fe8ca0 ./Essential_Game_Files/1161.VGA 51252981e969ad1d9f92cd9921199eb6 ./Essential_Game_Files/1162.VGA b05ab0b03954ff829ff6945059963c2f ./Essential_Game_Files/1171.VGA 69dd06969d3b64c9b1759fd0b792fedb ./Essential_Game_Files/1172.VGA 89f7e8e830e63cd91a2741041062c01a ./Essential_Game_Files/1181.VGA 0fdea1a722181204786346ebfab323c5 ./Essential_Game_Files/1182.VGA b3985bfd0448c0876eb3814576e47a86 ./Essential_Game_Files/1191.VGA 737f977e11c16b3ad8e9d83e3532a27d ./Essential_Game_Files/1192.VGA 898ebfe7fc3006c286245d6058c09e35 ./Essential_Game_Files/1201.VGA 2f8b8f89c6779b1239a933e257528db4 ./Essential_Game_Files/1202.VGA b3809b1968fcae950682df407003883b ./Essential_Game_Files/1211.VGA 4024f6a7dae0edb52a378db169e77b32 ./Essential_Game_Files/1212.VGA 7364747aac14421f05a843fa1136e65b ./Essential_Game_Files/1221.VGA 8d6daa45a034f77bac1d1c53503d658b ./Essential_Game_Files/1222.VGA bb9454789fa0350b079caeeff2991d5b ./Essential_Game_Files/1231.VGA ed32aa7e3f3141bbb007706ec3468162 ./Essential_Game_Files/1232.VGA 34ce97569163bd476d69eb4b073aa107 ./Essential_Game_Files/1241.VGA e1d4c78d2628cc925741f0168b4cf50d ./Essential_Game_Files/1242.VGA 698087f497a600946a00708e89ea6213 ./Essential_Game_Files/1251.VGA b1af97c56743e30d61b1bd73d716e2e8 ./Essential_Game_Files/1252.VGA 5ccaca4a804080c7046fd093ceb3c58c ./Essential_Game_Files/1261.VGA e20e77a408fdba0ee805d4b984cb81e1 ./Essential_Game_Files/1262.VGA f976644048d7b8ce7067e2f47728981f ./Essential_Game_Files/1271.VGA 4fd983abc568d148a756a6e0f9e3fccc ./Essential_Game_Files/1272.VGA 6fb3bd85891960cbd03e5bede83a5164 ./Essential_Game_Files/1281.VGA 7d6743c36079e05e0b8e742dbc6c6674 ./Essential_Game_Files/1282.VGA 90a663c8049219064fc225f666eec273 ./Essential_Game_Files/1291.VGA ac93dc37767c306db799554f7696adff ./Essential_Game_Files/1292.VGA 9b6a75c089e2d4b9bef591dab165392c ./Essential_Game_Files/1301.VGA 6fc4f5bf9e22542492769559b65c3ec0 ./Essential_Game_Files/1302.VGA 2305d4bb44b3d03cc301d71ea1dd00e4 ./Essential_Game_Files/1311.VGA 7a9b929200fbfbc57e16773eabd72349 ./Essential_Game_Files/1312.VGA 3741748a98403c8734a965f0f4ab639e ./Essential_Game_Files/1331.VGA ac7d0d37ecdb10e50d14ed612e8cbf79 ./Essential_Game_Files/1332.VGA 338b8621806b622bf34aa88928591de5 ./Essential_Game_Files/1481.VGA 8a84e75f9cb6137e21c299cd5aa5823e ./Essential_Game_Files/1482.VGA f0f39c94ef7ab9e66cad3b5c360a9717 ./Essential_Game_Files/1491.VGA b069ffaeca03749260cc55c65ebfa722 ./Essential_Game_Files/1492.VGA e5ff3ada2e94d682a56905beb8382a67 ./Essential_Game_Files/1501.VGA 3d73e76419585936e141fa6866fd4c21 ./Essential_Game_Files/1502.VGA d1e21c85cc5a400638526d1878112091 ./Essential_Game_Files/1511.VGA 786aa1579ee2dea9771ac0b61eb1d88e ./Essential_Game_Files/1512.VGA 1efce191b367fd655a7e8e6d586a223a ./Essential_Game_Files/1521.VGA 121c98babd5afd30e91f6807b2543f7d ./Essential_Game_Files/1522.VGA bc2939dd554564a65407b7be01ab0a8c ./Essential_Game_Files/1531.VGA 11ce4c6499631d2e460607b18a90183d ./Essential_Game_Files/1532.VGA 8f35ac30a7f0c025ddad8bf32a1e1a73 ./Essential_Game_Files/1541.VGA a82c33dae03b5089d5a60a5bd8c0ac09 ./Essential_Game_Files/1542.VGA 726e491cec0d18880d8b78cdbd50d19b ./Essential_Game_Files/1551.VGA 32077dd343f45329bc4d3112c56e87ff ./Essential_Game_Files/1552.VGA a4cf19056b228a02c2bf32b31082326e ./Essential_Game_Files/1561.VGA 782da97fb7e703da8fd990c152a78012 ./Essential_Game_Files/1562.VGA 80885bd0f3734f989653c4782c56e5d4 ./Essential_Game_Files/1571.VGA 903aebe1ab59863cd5f70344fe3317c9 ./Essential_Game_Files/1572.VGA 82c306723db9d3389654f78c58b0de23 ./Essential_Game_Files/1581.VGA 600154f723f0b76a0fb6f341f2941caa ./Essential_Game_Files/1582.VGA f45b09c0b1eb3ce58f1f48497b14ba3d ./Essential_Game_Files/1591.VGA e7b21fdd3017e4c40696789799ae5a9c ./Essential_Game_Files/1592.VGA c8cbc1f3c11db6149275fa318478dee5 ./Essential_Game_Files/1601.VGA 9faf19c66b4c3da420ee854676f562d0 ./Essential_Game_Files/1602.VGA 2c279669bf94928727ee218f371b1793 ./Essential_Game_Files/1611.VGA 038846d32d0819380fca2fa028c17304 ./Essential_Game_Files/1612.VGA 342c5835e2bb1b1d78769940c83b02a0 ./Essential_Game_Files/1621.VGA 274fdffadc4f4b8cde034fe849d70b6a ./Essential_Game_Files/1622.VGA c30500ebd8262fc184b4fd9563e60bce ./Essential_Game_Files/1631.VGA 0d8c3c62a2ea4a71a9cdfbc6a4386cd8 ./Essential_Game_Files/1632.VGA 378b2b079f4ad4dd1fe864521973e0b9 ./Essential_Game_Files/1641.VGA 7893ef7fdd5299dd703d1a7f18d4e448 ./Essential_Game_Files/1642.VGA ddf4c52413f1d42cea807b8bdacaf5e7 ./Essential_Game_Files/1651.VGA b3b5f63503b1510eb18ae4d15f787ab9 ./Essential_Game_Files/1652.VGA 506c6eb8c776e1dd1f5557cf155f5641 ./Essential_Game_Files/1661.VGA f2fc995fa47a7b0a6eee94e79c83efc0 ./Essential_Game_Files/1662.VGA 670310ad34d3dad9c48c622aa3db8fcf ./Essential_Game_Files/1671.VGA 4e4d504e1c0cc998c365eecfb7e122c7 ./Essential_Game_Files/1672.VGA a64dc64018ab021002b2958f7c2b255c ./Essential_Game_Files/1681.VGA c88f26d2037af9cc6231a09ed36efbcc ./Essential_Game_Files/1682.VGA 307006e98381d7707c871e7c6d6402fa ./Essential_Game_Files/1691.VGA cfc3f1f01b43d5c7a72451250c57f6f2 ./Essential_Game_Files/1692.VGA 788dd8e2cd6140a7bd94785fe36930dd ./Essential_Game_Files/1701.VGA 4ff08bbebe92c6c8592a3fe454b1b095 ./Essential_Game_Files/1702.VGA 5f11f1d6b9eeb2e7a3957e3faae5a3e3 ./Essential_Game_Files/1711.VGA 68a729ae1d001d35db99e930db7de219 ./Essential_Game_Files/1712.VGA 98c044a423bbb7bd7274072960a2e9f6 ./Essential_Game_Files/1731.VGA 88daa0b4de221496dedf63d9d3367ef2 ./Essential_Game_Files/1732.VGA c53745039b6466033b6647462aff4945 ./Essential_Game_Files/1781.VGA c836cc779f4a2482a625ffbfca2619dc ./Essential_Game_Files/1782.VGA e9a4e093d54136845d584bda2a7f5e38 ./Essential_Game_Files/1791.VGA ac820b2784043ef4c352adba4965c1c2 ./Essential_Game_Files/1792.VGA a3f9a3a4c8b5943288465f9a4bf66ec1 ./Essential_Game_Files/1801.VGA 630a8a296ed0943289c5cd52441e9151 ./Essential_Game_Files/1802.VGA 0bac8878919f5ec3c282f120521bb50b ./Essential_Game_Files/1811.VGA 87a1da2123cd63d649c64a7bcefafde7 ./Essential_Game_Files/1812.VGA 05e4381ab638fae633480ffadf73915b ./Essential_Game_Files/1821.VGA 9fe8aa1a06a82b4ff94b8185ba848dd0 ./Essential_Game_Files/1822.VGA 456c7e4df8dda20fc4191a2ab451a23a ./Essential_Game_Files/1831.VGA 197cb37e6920ee2d62094d822d9e29b8 ./Essential_Game_Files/1832.VGA 4d1e8a2c6c61493c1d531ba17ec46e06 ./Essential_Game_Files/1841.VGA 9b8bf064d6c967c6ac713dfaa84d9501 ./Essential_Game_Files/1842.VGA b24e6f1b5ab2a917c0ab3a1494fd0659 ./Essential_Game_Files/1851.VGA 8529e139e90d3b76bda87c0b3a0bc427 ./Essential_Game_Files/1852.VGA b51e9317ff2fb65971820e306cbf0a73 ./Essential_Game_Files/1861.VGA 8a385b653e0deb0483967193b11bae4e ./Essential_Game_Files/1862.VGA f8d5f44fca5d761d1f00b7713e02988e ./Essential_Game_Files/1871.VGA c4f7ec874c7165ad245d4178179669f1 ./Essential_Game_Files/1872.VGA 7481e4db932e6c1114acc52991183813 ./Essential_Game_Files/1881.VGA b1b359f5a913fbac6bbb9b4d19c61f2d ./Essential_Game_Files/1882.VGA b2ff7049dcf6b38912a3649120d5cc6c ./Essential_Game_Files/1891.VGA 56a6d12448b383c9cf4f966131e9fd48 ./Essential_Game_Files/1892.VGA 91bdbcc4559138f5a21457deb7f70a03 ./Essential_Game_Files/1901.VGA a284ac4e9e8a4df4e830a8dbec247739 ./Essential_Game_Files/1902.VGA 74c17cbafa309194732fb0c00dd95375 ./Essential_Game_Files/1911.VGA b6026825655bea901d1e7deea46106cb ./Essential_Game_Files/1912.VGA 59665be5b0899223b77e70dfaf55ac69 ./Essential_Game_Files/1921.VGA 4534fa783f9a2f9f2b2d00e28d1df42c ./Essential_Game_Files/1922.VGA a0e3de5f40aa459ef10a295f405e16e6 ./Essential_Game_Files/1931.VGA edfbcbdb2af8d24c8bfcd39de6b2980e ./Essential_Game_Files/1932.VGA 3ef8366f6ada98ca4228fa6e9ac5231a ./Essential_Game_Files/1941.VGA bafc7bde7289261c822522bc886d7b99 ./Essential_Game_Files/1942.VGA 72e4fc26559a8a8f385dfc90385c8552 ./Essential_Game_Files/1951.VGA 4bb17129b4811fc70380e3f4c0b61943 ./Essential_Game_Files/1952.VGA 37dc35fd7eba04d0df200152e39d88b1 ./Essential_Game_Files/1961.VGA 0ac6854bac184b9e0869bd7477cf312e ./Essential_Game_Files/1962.VGA 910a7c58b33d8ef3d125f1fef552c387 ./Essential_Game_Files/1971.VGA ffba66f7b272cf0741c038608b075c67 ./Essential_Game_Files/1972.VGA 4c074f4f6802a87b3b3a40ea48204fba ./Essential_Game_Files/1981.VGA 599f81669d4985b0539916191b3933f9 ./Essential_Game_Files/1982.VGA f8f758023dc5acc97c734efd1dc38289 ./Essential_Game_Files/1991.VGA fb2725ca20a497c88e3e906b6b6e11d0 ./Essential_Game_Files/1992.VGA 76207006986c448e87f4b2b722e27ccd ./Essential_Game_Files/2001.VGA 8388bc06ce0949dbab302a8dd61aac89 ./Essential_Game_Files/2002.VGA c7da916b388d56179dc7f123a80ee100 ./Essential_Game_Files/2011.VGA 1782f9682ca097688f2cc1817b841788 ./Essential_Game_Files/2012.VGA 7d858a740d615b45543775716cc5809b ./Essential_Game_Files/2031.VGA f5c453b0dd535585504b3a84299d9c73 ./Essential_Game_Files/2032.VGA c372995d226110ccd998bc32be528ab7 ./Essential_Game_Files/2081.VGA 8eb186cb31972c79ef218329e7b41229 ./Essential_Game_Files/2082.VGA a002752971d770831970e9dac980d73c ./Essential_Game_Files/2091.VGA 6ad24fb52539de2f5dae6ba68211811f ./Essential_Game_Files/2092.VGA b05ca02618030684246893c84531d4da ./Essential_Game_Files/2101.VGA 4988325e603c726a35f94ac8216421bd ./Essential_Game_Files/2102.VGA 6e2af23932f5e31c1d28415686985cba ./Essential_Game_Files/2111.VGA 6d413abed1e45de7b001d4ee5cafca7c ./Essential_Game_Files/2112.VGA 3d993e487b20a548d2111d51e93abe96 ./Essential_Game_Files/2121.VGA 92533aba54fb5dbd8bb3185a26f617f8 ./Essential_Game_Files/2122.VGA 014b9aa02c536d9c63caeaba00868eba ./Essential_Game_Files/2131.VGA 1f5a1d19324b5076c6d46240e3b1b41b ./Essential_Game_Files/2132.VGA ad288a6147b1961501408a28ad6ec09d ./Essential_Game_Files/2141.VGA 06bf52a316b0583b4119db39ab99402e ./Essential_Game_Files/2142.VGA f03bb4b2b1febd48941392d930b6b628 ./Essential_Game_Files/2151.VGA 3598ce89ac8683338792bb1f09e23660 ./Essential_Game_Files/2152.VGA 999bc48efb6ab23533349f51f7f633e1 ./Essential_Game_Files/2161.VGA 3c0356bfb35f3d1bbff6fa9f1b1f03d7 ./Essential_Game_Files/2162.VGA 8651a075902cbd628874c05cca5f5ecc ./Essential_Game_Files/2171.VGA 7f1979d31c9f0434c788d663c63a2619 ./Essential_Game_Files/2172.VGA 7e2e8b971f297be6f590074cb10aeb85 ./Essential_Game_Files/2181.VGA b5f1db3aa2b9d6d11fe646c7f6bd0207 ./Essential_Game_Files/2182.VGA 44735dcd64a24f528bc0f6661d83acb4 ./Essential_Game_Files/2191.VGA 36868fca049e24924d372dfbc9c9508a ./Essential_Game_Files/2192.VGA 8c7787ac2e33cd80cc9c762aa20b9a60 ./Essential_Game_Files/2201.VGA 36c7e4b15dd6d65b85a3413431d5e572 ./Essential_Game_Files/2202.VGA 98b38d95e2e84e4a7716fcf929d01845 ./Essential_Game_Files/2211.VGA fa5a040398498ed4f9abac267fd6f46c ./Essential_Game_Files/2212.VGA 954b5e5046713f2e6647dc713c90795a ./Essential_Game_Files/2221.VGA acfc543fe2830bad6abc4f5803fd5afb ./Essential_Game_Files/2222.VGA b1677301a1c83baddb98f538e1e7e905 ./Essential_Game_Files/2231.VGA b00f7c4b9ad4e1b02cced028a1ee1316 ./Essential_Game_Files/2232.VGA 192418ff6dbe40f847a2c57abda1379f ./Essential_Game_Files/2241.VGA f49acbd2a28a1ba3abff4243beb10169 ./Essential_Game_Files/2242.VGA b81f4715ed83e27da66c3bd6ae41990d ./Essential_Game_Files/2251.VGA 11e8d550a5c900b32e6549b7606c6454 ./Essential_Game_Files/2252.VGA 0cb960a584687ec64da0241c15fe6557 ./Essential_Game_Files/2261.VGA 395cd6d9d7e10e45929344c1d2171f51 ./Essential_Game_Files/2262.VGA 53e52e94b0256b968ff87e285c787804 ./Essential_Game_Files/2271.VGA 4b91a65435425e08e5aec48c124d672f ./Essential_Game_Files/2272.VGA 82ba12c23bbf34cf69f000a876e1347f ./Essential_Game_Files/2281.VGA 3c8103092f09ac2da548256143f10c75 ./Essential_Game_Files/2282.VGA f85961c60c6a9260dcb9d1b6461d2257 ./Essential_Game_Files/2291.VGA 11a3c497cda55d1c7ba3ed616d8eb17d ./Essential_Game_Files/2292.VGA e889c6dc9e4cead3a2527c0232b50cd4 ./Essential_Game_Files/2301.VGA c71ddf8137ea8033dec8ba91746f9c86 ./Essential_Game_Files/2302.VGA c9179570006769e13b55faa9f85d062f ./Essential_Game_Files/2311.VGA 13f73e64b06ff9699f18486be4799a0c ./Essential_Game_Files/2312.VGA 351f215213ca37127114a8ead93dc143 ./Essential_Game_Files/2331.VGA bfd9efa445d5d1d99d0e658cfea040f8 ./Essential_Game_Files/2332.VGA 641f9bb60ad62328bafda1e61a4a9493 ./Essential_Game_Files/3081.VGA 586bd630d6d33e2fcec944b7177f0317 ./Essential_Game_Files/3082.VGA 469d45b820d841cc896fc3496cdd96dc ./Essential_Game_Files/3091.VGA a85b8268dc5753c1cd821c266ff6a74f ./Essential_Game_Files/3092.VGA 854556ee6e2027687c570a7c6afdcbbf ./Essential_Game_Files/3101.VGA 9ea6b3c7ce56aadcf86f1926e5c9b3e0 ./Essential_Game_Files/3102.VGA 2548c35a794702194e91405d317bf478 ./Essential_Game_Files/3111.VGA 51552f158c3bb62ccb9ddfd1f0ff2327 ./Essential_Game_Files/3112.VGA f604de01409a18359053aca51778bbd2 ./Essential_Game_Files/3121.VGA 09c0751817996596d17944c411b2a6b6 ./Essential_Game_Files/3122.VGA 315ed5cd6409e5ad104831acdce4c870 ./Essential_Game_Files/3131.VGA 96e9d946dfa3dbc20fc40bf6c8f116a2 ./Essential_Game_Files/3132.VGA 3a7c86afdf6e76d0cb6e1c90ea056e79 ./Essential_Game_Files/3141.VGA 09eef60be0f9547424b86f75914fe99a ./Essential_Game_Files/3142.VGA fb3a76e829736bfdc5634b102440fe2a ./Essential_Game_Files/3151.VGA d9bcf154ec98dea1079390e9cdd0ced4 ./Essential_Game_Files/3152.VGA cc6c3fd714b9f507eaba29b463482c0d ./Essential_Game_Files/3161.VGA 0e3fe912b9fba729c6e70c9b8063afda ./Essential_Game_Files/3162.VGA cfc42f8f5a1760eaecd2a8ce518ef605 ./Essential_Game_Files/3171.VGA 5beb574fbb5e092ccc9778fc00b31733 ./Essential_Game_Files/3172.VGA fed6730618a4c98efb99b07d9fdb77df ./Essential_Game_Files/3181.VGA 0f591dc333891cdfef91737d964c3439 ./Essential_Game_Files/3182.VGA 5f358183d95b1dae608dd4b8213b46fc ./Essential_Game_Files/3191.VGA 51f56a4fa58e5b57b626f8a4b6b1eadd ./Essential_Game_Files/3192.VGA cc9e195f163eb32bde0bfea8ef99c744 ./Essential_Game_Files/3201.VGA 9d0f18393479cd6c5907598436fdeeaa ./Essential_Game_Files/3202.VGA bd2bc7335e61ed6d5a452430542a871a ./Essential_Game_Files/3211.VGA 13eff9f493356cd2687facc6172eca95 ./Essential_Game_Files/3212.VGA 4794ca9a6588dd9effba904e58f06a92 ./Essential_Game_Files/3221.VGA 33da9dca33f1f894046e26561c8104a6 ./Essential_Game_Files/3222.VGA e7d4d01abd11a1a7b6913696aea9fe32 ./Essential_Game_Files/3231.VGA d46406bc43e7a96f3d36c5ef6ac76594 ./Essential_Game_Files/3232.VGA 4d1f25a113f1193d5be94918b0b89d11 ./Essential_Game_Files/3241.VGA f8b77a428a76f77368c54a69baec3a93 ./Essential_Game_Files/3242.VGA ebedf64ff02c4ee75d5f66af9177c8ac ./Essential_Game_Files/3251.VGA 8ed0d4ed5ad93e41c730ff786b25e2ca ./Essential_Game_Files/3252.VGA bd974efc711841c9e5184ba0cc910973 ./Essential_Game_Files/3261.VGA f4104d2e8a88cf79181a7fee1236bc7b ./Essential_Game_Files/3262.VGA 10a8b55ef89c778b47ae6f8e9b83070d ./Essential_Game_Files/3271.VGA c1e07bf55bae6c675bb902f156a1c0a0 ./Essential_Game_Files/3272.VGA de77d1f526caedb63b67aa5e58319e4e ./Essential_Game_Files/3281.VGA 98f3f76926bfadb3d1adcbfdf1387be4 ./Essential_Game_Files/3282.VGA 40f2cf5e69e017c32e1f3c310559af4c ./Essential_Game_Files/3291.VGA 4582764bc765be9599f471c29edf1d3d ./Essential_Game_Files/3292.VGA 7c4cbdb31308305a3c6ceba62fb4e2e2 ./Essential_Game_Files/3301.VGA 70df5e0ed6f4b182095604c1aaa19df1 ./Essential_Game_Files/3302.VGA f1be13ed49dde47d1153a94c28bd8ca5 ./Essential_Game_Files/3311.VGA 26cfa5b4d84fec889c3c3a12829c3764 ./Essential_Game_Files/3312.VGA 969521951494ee79bbabd3674747046a ./Essential_Game_Files/3331.VGA aeb37c757f102ff4ca3d76db07eec04c ./Essential_Game_Files/3332.VGA 6aa0544fdfd9cc86ce6e72ca05d1433f ./Essential_Game_Files/Charisma.smk 31efba0e0f105ecdf77a8fe63db90ed3 ./Essential_Game_Files/Disk1.smk ecb26c965ca8b45e3a1856fc17a21b9e ./Essential_Game_Files/Disk2.smk b8f09cb0f9d811c32e5bdb07aac08584 ./Essential_Game_Files/Disk3.smk f2ce346f8f45c0d362f432ad5fe1b6dd ./Essential_Game_Files/Disk4.smk ae84d7898b6282127618069d9c586246 ./Essential_Game_Files/feeinbin.ico 24fe7ba975369c272088aa3b0c5bf348 ./Essential_Game_Files/GAME22 c1fa9f0e1726e9a95638b53b1d087468 ./Essential_Game_Files/icklfeeb.ico e445a0a7e554ebcb550a52ee6e74023e ./Essential_Game_Files/Nextdoor.smk c86a414aa0101d0838b6c5e20dd5e99c ./Essential_Game_Files/Omnitoy.smk 754e03f61a1186dd47b31ee7798fc704 ./Essential_Game_Files/Qtime.smk c4a0b8193335026c5b220257dea2c585 ./Essential_Game_Files/Run95.exe 71512fc98501a8071a26b683a31dde78 ./Essential_Game_Files/save.999 7635d1e15ba1704b3cb1525c1eba0d6f ./Essential_Game_Files/SMACKW32.DLL e00cead9fb77c8a6b48b9a8fe98af527 ./Essential_Game_Files/startup.wav 4157c16894c0413ca64e56a52aa46d50 ./Essential_Game_Files/TABLES01 d71b7918c74a999fa4c539ee8ef63003 ./Essential_Game_Files/TABLES02 ae33ef52caed416c1f29c2976736ac4f ./Essential_Game_Files/TABLES03 7edccf6dda9b1007a039a04980d06d88 ./Essential_Game_Files/TABLES04 5fdf13ec87decd2f48686e0a29cd880f ./Essential_Game_Files/TABLES05 660915b818d654b09a30d0ca8536e21a ./Essential_Game_Files/TABLES06 597d9304e3a1f354f39f81b6b538a395 ./Essential_Game_Files/TABLES07 243c717ab93de8c3064eda96d575f617 ./Essential_Game_Files/TABLES08 c0284a4c084db9bf4ce02c89f8842153 ./Essential_Game_Files/TABLES09 743ddf7cdd9488d74a840180fe71d468 ./Essential_Game_Files/TABLES10 0f1fdab8f4cc2dea3f29058250b82068 ./Essential_Game_Files/TABLES11 94b6a25599dfaaea64cb3a7a4a1c7589 ./Essential_Game_Files/TABLES12 773d8084c0b3a98b1c9b556768cbb564 ./Essential_Game_Files/TABLES13 4d7771240870c4a7e5b0f4b4a2e010f7 ./Essential_Game_Files/TABLES14 3718ba2c338b75bebe4709b939de7542 ./Essential_Game_Files/TABLES15 7de9a7487fe332e41041a39b10eac54d ./Essential_Game_Files/TABLES16 b9e5112e0462b7d69f218e64883193a9 ./Essential_Game_Files/TABLES17 a3a740286dfbb33f52d7a5cfb1ce51a7 ./Essential_Game_Files/TABLES18 dc5d78aa8377d0e85381a3768742f834 ./Essential_Game_Files/TABLES19 a528ec6eed4f050c492a1e89aa03f480 ./Essential_Game_Files/TABLES20 c521eb8fe621ddb1a1e112fc679ef1b4 ./Essential_Game_Files/TABLES21 6fc3c61399faee65d26451132ff94b94 ./Essential_Game_Files/TABLES22 41383b96f63ede313c7f698027a6fb5d ./Essential_Game_Files/TABLES23 b50f2a67685e05b792afd5edf894ebeb ./Essential_Game_Files/TABLES24 a7add5ae7548d332982c234a81bfb03f ./Essential_Game_Files/TABLES25 0bbfee8e69739111eb36b0d138da8ddf ./Essential_Game_Files/TBLLIST unshield-1.4.2/test/v0/the-feeble-files-spanish.sh000077500000000000000000000016071303674433700217550ustar00rootroot00000000000000#!/bin/bash set -e cd `dirname $0` MD5_FILE=`pwd`/`basename $0 .sh`.md5 UNSHIELD=${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.dropbox.com/s/1ng0z9kfxc7eb1e/unshield-the-feeble-files-spanish.zip?dl=1" curl -fsSL -o test.zip ${URL} unzip -q test.zip 'data*' set +e timeout 10 ${UNSHIELD} -O -d extract1 x data1.cab > log2 2>&1 CODE=$? if [ ${CODE} -ne 0 ]; then cat log2 >&2 echo "unshield failed with error $CODE" >&2 echo "See https://github.com/twogood/unshield/issues/27" >&2 exit 2 fi cd extract1 find . -type f | sort | xargs md5sum > ../md5 if ! diff ${MD5_FILE} ../md5 >&2 ; then echo "MD5 sums diff" >&2 echo "See https://github.com/twogood/unshield/issues/27" >&2 exit 3 fi exit 0 unshield-1.4.2/test/v5/000077500000000000000000000000001303674433700146545ustar00rootroot00000000000000unshield-1.4.2/test/v5/CVE-2015-1386/000077500000000000000000000000001303674433700162555ustar00rootroot00000000000000unshield-1.4.2/test/v5/CVE-2015-1386/CVE-2015-1386.sh000077500000000000000000000013211303674433700202120ustar00rootroot00000000000000#!/bin/bash set -e cd `dirname $0` MD5_FILE=`pwd`/`basename $0 .sh`.md5 CAB_FILE=`pwd`/data1.cab UNSHIELD=${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 unshield-1.4.2/test/v5/CVE-2015-1386/data1.cab000066400000000000000000000010101303674433700177060ustar00rootroot00000000000000ISc(R^8wd ?Ȁ8wd Wwd Wwd pNG?NWcqcz'3K =YuProgram FilesBovine FilesBovine FilesCompactProgram FilesMainStartupBovine FilesProgram Files>hX. 9)C2 $+u 9FeN 9FeN../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../tmp/moounshield-1.4.2/valgrind.sh000077500000000000000000000001511303674433700155050ustar00rootroot00000000000000#!/bin/sh libtool --mode=execute valgrind --num-callers=10 --leak-check=yes `dirname $0`/src/unshield $@