├── .gitignore ├── bin └── .gitignore ├── jni ├── Application.mk └── Android.mk ├── src ├── utils.h ├── log.h ├── Makefile ├── common.h ├── sha1.h ├── log.c ├── utils.c ├── dexRepair.c ├── dex.h └── sha1.c ├── make.sh └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | src/*.o 2 | src/dexRepair 3 | obj 4 | libs 5 | bin/* 6 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | # Dex Repair 2 | # ----------------------------------------- 3 | # 4 | # Anestis Bechtsoudis 5 | # Copyright 2015-2017 by CENSUS S.A. All Rights Reserved. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | APP_PLATFORM := android-21 20 | APP_ABI := armeabi armeabi-v7a arm64-v8a x86 x86_64 21 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DEX Repair 4 | ----------------------------------------- 5 | 6 | Anestis Bechtsoudis 7 | Copyright 2015-2016 by CENSUS S.A. All Rights Reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | */ 22 | 23 | #ifndef _UTILS_H_ 24 | #define _UTILS_H_ 25 | 26 | #include 27 | 28 | bool utils_init(infiles_t*); 29 | 30 | uint8_t* utils_mapFileToRead(char*, off_t*, int*); 31 | 32 | bool utils_writeToFd(int, uint8_t*, off_t); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | # Dex Repair 2 | # ----------------------------------------- 3 | # 4 | # Anestis Bechtsoudis 5 | # Copyright 2015-2017 by CENSUS S.A. All Rights Reserved. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | LOCAL_PATH := $(call my-dir) 20 | 21 | # Main module 22 | include $(CLEAR_VARS) 23 | LOCAL_MODULE := dexRepair 24 | SRC := ../src 25 | LOCAL_SRC_FILES := $(SRC)/dexRepair.c $(SRC)/log.c $(SRC)/utils.c $(SRC)/sha1.c 26 | LOCAL_CFLAGS += -c -std=c11 -D_GNU_SOURCE \ 27 | -Wall -Wextra -Werror 28 | LOCAL_LDFLAGS += -lm -lz 29 | include $(BUILD_EXECUTABLE) 30 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DEX Repair 4 | ----------------------------------------- 5 | 6 | Anestis Bechtsoudis 7 | Copyright 2015-2016 by CENSUS S.A. All Rights Reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | */ 22 | 23 | #ifndef _LOG_H_ 24 | #define _LOG_H_ 25 | 26 | typedef enum { 27 | l_FATAL = 0, l_ERROR, l_WARN, l_INFO, l_DEBUG 28 | } log_level_t; 29 | 30 | extern void log_setMinLevel(log_level_t dl); 31 | 32 | extern void log_msg(log_level_t dl, bool perr, const char *file, const char *func, int line, 33 | const char *fmt, ...); 34 | 35 | #define LOGMSG(ll, ...) log_msg(ll, false, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); 36 | #define LOGMSG_P(ll, ...) log_msg(ll, true, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # Dex Repair 2 | # ----------------------------------------- 3 | # 4 | # Anestis Bechtsoudis 5 | # Copyright 2015-2016 by CENSUS S.A. All Rights Reserved. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | # Default to gcc 20 | CC ?= gcc 21 | 22 | TARGET = dexRepair 23 | CFLAGS += -c -std=c11 -D_GNU_SOURCE \ 24 | -Wall -Wextra -Werror 25 | LDFLAGS += -lm -lz 26 | 27 | .PHONY: default all clean 28 | 29 | default: $(TARGET) 30 | all: default 31 | 32 | OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) 33 | HEADERS = $(wildcard *.h) 34 | 35 | %.o: %.c $(HEADERS) 36 | $(CC) $(CFLAGS) -c $< -o $@ 37 | 38 | .PRECIOUS: $(TARGET) $(OBJECTS) 39 | 40 | $(TARGET): $(OBJECTS) 41 | $(CC) $(OBJECTS) $(LDFLAGS) -o $@ 42 | cp $(TARGET) ../bin/$(TARGET) 43 | 44 | clean: 45 | -rm -f *.o 46 | -rm -f $(TARGET) 47 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DEX Repair 4 | ----------------------------------------- 5 | 6 | Anestis Bechtsoudis 7 | Copyright 2015-2016 by CENSUS S.A. All Rights Reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | */ 22 | 23 | #ifndef _COMMON_H_ 24 | #define _COMMON_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #define PROG_NAME "DEX Repair" 35 | #define PROG_VERSION "0.1.4" 36 | #define PROG_AUTHORS " Anestis Bechtsoudis \n"\ 37 | " Copyright 2015-2017 by CENSUS S.A. All Rights Reserved." 38 | 39 | #define AB ANSI_BOLD 40 | #define AC ANSI_CLEAR 41 | #define ANSI_BOLD "\033[1m" 42 | #define ANSI_CLEAR "\033[0m" 43 | 44 | typedef struct { 45 | char *inputFile; 46 | char **files; 47 | size_t fileCnt; 48 | } infiles_t; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # fail on unhandled error 4 | set -u # fail on undefined variable 5 | #set -x # debug 6 | 7 | declare -a sysTools=( "make" ) 8 | 9 | function commandExists() 10 | { 11 | type "$1" &> /dev/null 12 | } 13 | 14 | function usage() 15 | { 16 | echo "$(basename "$0") [gcc|clang|cross-android] (default is gcc)" 17 | exit 1 18 | } 19 | 20 | function build_cross_android() 21 | { 22 | local cpu cpuBaseDir 23 | if [[ -z ${NDK+x} ]]; then 24 | # Search in $PATH 25 | if [[ $(which ndk-build) != "" ]]; then 26 | NDK=$(dirname "$(which ndk-build)") 27 | else 28 | echo "[-] Could not detect Android NDK dir" 29 | exit 1 30 | fi 31 | fi 32 | 33 | ndk-build clean 34 | ndk-build || { 35 | echo "[-] android build failed" 36 | exit 1 37 | } 38 | 39 | find libs -type d -mindepth 1 -maxdepth 1 | while read -r cpuBaseDir 40 | do 41 | cpu=$(basename "$cpuBaseDir") 42 | cp libs/"$cpu"/dexRepair bin/dexRepair-"$cpu" 43 | done 44 | } 45 | 46 | function build() 47 | { 48 | local compiler="$1" 49 | 50 | make clean -C src || { 51 | echo "[-] make clean failed" 52 | exit 1 53 | } 54 | 55 | CC=$compiler make -C src || { 56 | echo "[-] clang build failed" 57 | exit 1 58 | } 59 | } 60 | 61 | # Check that common system tools exist 62 | for i in "${sysTools[@]}" 63 | do 64 | if ! commandExists "$i"; then 65 | echo "[-] '$i' command not found" 66 | exit 1 67 | fi 68 | done 69 | 70 | if [ $# -gt 1 ]; then 71 | echo "[-] Invalid args" 72 | exit 1 73 | fi 74 | 75 | if [ $# -eq 0 ]; then 76 | target="" 77 | else 78 | target="$1" 79 | fi 80 | 81 | case "$target" in 82 | "") build "gcc";; 83 | "gcc") build "gcc";; 84 | "clang") build "clang";; 85 | "cross-android") build_cross_android;; 86 | *) usage;; 87 | esac 88 | 89 | exit 0 90 | -------------------------------------------------------------------------------- /src/sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Description: 5 | * This is the header file for code which implements the Secure 6 | * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published 7 | * April 17, 1995. 8 | * 9 | * Many of the variable names in this code, especially the 10 | * single character names, were used because those were the names 11 | * used in the publication. 12 | * 13 | * Please read the file sha1.c for more information. 14 | * 15 | */ 16 | 17 | #ifndef _SHA1_H_ 18 | #define _SHA1_H_ 19 | 20 | #include 21 | /* 22 | * If you do not have the ISO standard stdint.h header file, then you 23 | * must typdef the following: 24 | * name meaning 25 | * uint32_t unsigned 32 bit integer 26 | * uint8_t unsigned 8 bit integer (i.e., unsigned char) 27 | * int_least16_t integer of >= 16 bits 28 | * 29 | */ 30 | 31 | #ifndef _SHA_enum_ 32 | #define _SHA_enum_ 33 | enum 34 | { 35 | shaSuccess = 0, 36 | shaNull, /* Null pointer parameter */ 37 | shaInputTooLong, /* input data too long */ 38 | shaStateError /* called Input after Result */ 39 | }; 40 | #endif 41 | #define SHA1HashSize 20 42 | 43 | /* 44 | * This structure will hold context information for the SHA-1 45 | * hashing operation 46 | */ 47 | typedef struct SHA1Context 48 | { 49 | uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 50 | 51 | uint32_t Length_Low; /* Message length in bits */ 52 | uint32_t Length_High; /* Message length in bits */ 53 | 54 | /* Index into message block array */ 55 | int_least16_t Message_Block_Index; 56 | uint8_t Message_Block[64]; /* 512-bit message blocks */ 57 | 58 | int Computed; /* Is the digest computed? */ 59 | int Corrupted; /* Is the message digest corrupted? */ 60 | } SHA1Context; 61 | 62 | /* 63 | * Function Prototypes 64 | */ 65 | 66 | int SHA1Reset( SHA1Context *); 67 | int SHA1Input( SHA1Context *, 68 | const uint8_t *, 69 | unsigned int); 70 | int SHA1Result( SHA1Context *, 71 | uint8_t Message_Digest[SHA1HashSize]); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Dex Repair 2 | 3 | Command line tool to repair Android DEX bytecode files CRC checksum and SHA-1 4 | hash 5 | 6 | 7 | ## Compile 8 | 9 | * Clone this repository 10 | * Install Android NDK if you want to cross-compile for Android devices 11 | * Invoke `make.sh` bash script with desired build target 12 | * `$ ./make.sh` - default system compiler 13 | * `$ ./make.sh gcc` - prefer gcc 14 | * `$ ./make.sh clang` - prefer clang 15 | * `$ ./make.sh cross-android` - cross-compile for Android with NDK 16 | * Executables are copied under the `bin` directory 17 | 18 | 19 | ## Usage 20 | 21 | ``` 22 | $ bin/dexRepair -h 23 | DEX Repair ver. 0.1.4 24 | 25 | Anestis Bechtsoudis 26 | Copyright 2015-2017 by CENSUS S.A. All Rights Reserved. 27 | 28 | -I, --input-files=DIR : input files dirs (1 level recursion only) or single file 29 | -S, --repair-sha : repair SHA-1 hash too (default: disabled) 30 | -h, --help : this help 31 | -v, --debug=LEVEL : debug level (0 - FATAL ... 4 - DEBUG), default: '3' (INFO) 32 | ``` 33 | 34 | 35 | ## Changelog 36 | 37 | * __0.1.4__ - 13 October 2017 38 | * Dex version 038 (Oreo) & 039 (dev-master) support 39 | * __0.1.3__ - 26 April 2017 40 | * Support to repair SHA-1 hash too 41 | * __0.1.2__ - 24 April 2017 42 | * Refactor readdir utils 43 | * Improve make script & Android.mk 44 | * __0.1.1__ - 5 September 2016 45 | * Add support for ODEX 037 format 46 | * __0.1.0__ - 14 February 2015 47 | * Initial commit 48 | 49 | 50 | ## License 51 | 52 | ``` 53 | Anestis Bechtsoudis 54 | Copyright 2015-2017 by CENSUS S.A. All Rights Reserved. 55 | 56 | Licensed under the Apache License, Version 2.0 (the "License"); 57 | you may not use this file except in compliance with the License. 58 | You may obtain a copy of the License at 59 | 60 | http://www.apache.org/licenses/LICENSE-2.0 61 | 62 | Unless required by applicable law or agreed to in writing, software 63 | distributed under the License is distributed on an "AS IS" BASIS, 64 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 | See the License for the specific language governing permissions and 66 | limitations under the License. 67 | ``` 68 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DEX Repair 4 | ----------------------------------------- 5 | 6 | Anestis Bechtsoudis 7 | Copyright 2015-2016 by CENSUS S.A. All Rights Reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "common.h" 29 | #include "log.h" 30 | 31 | #define STDOUT_FD 1 32 | 33 | unsigned int log_minLevel; 34 | bool log_isStdioTTY; 35 | 36 | __attribute__ ((constructor)) 37 | void log_init(void) 38 | { 39 | log_minLevel = l_INFO; 40 | if (isatty(STDOUT_FD) == 1) { 41 | log_isStdioTTY = true; 42 | } else { 43 | log_isStdioTTY = false; 44 | } 45 | } 46 | 47 | void log_setMinLevel(log_level_t dl) 48 | { 49 | log_minLevel = dl; 50 | } 51 | 52 | void log_msg(log_level_t dl, bool perr, const char *file, 53 | const char *func, int line, const char *fmt, ...) 54 | { 55 | struct { 56 | char *descr; 57 | char *prefix; 58 | } logLevels[] = { 59 | { 60 | "[FATAL]", "\033[1;31m"}, { 61 | "[ERROR]", "\033[1;35m"}, { 62 | "[WARNING]", "\033[1;34m"}, { 63 | "[INFO]", "\033[1m"}, { 64 | "[DEBUG]", "\033[0;37m"} 65 | }; 66 | 67 | char strerr[512]; 68 | if (perr) { 69 | snprintf(strerr, sizeof(strerr), "%s", strerror(errno)); 70 | } 71 | 72 | if (dl > log_minLevel) 73 | return; 74 | 75 | struct tm tm; 76 | struct timeval tv; 77 | 78 | gettimeofday(&tv, NULL); 79 | localtime_r((const time_t *)&tv.tv_sec, &tm); 80 | 81 | if (log_isStdioTTY) { 82 | printf("%s", logLevels[dl].prefix); 83 | } 84 | 85 | if (log_minLevel >= l_DEBUG || !log_isStdioTTY) { 86 | printf 87 | ("%s [%d] %d/%02d/%02d %02d:%02d:%02d (%s:%s %d) ", 88 | logLevels[dl].descr, getpid(), tm.tm_year + 1900, tm.tm_mon + 1, 89 | tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, file, func, line); 90 | } else { 91 | printf("%s ", logLevels[dl].descr); 92 | } 93 | 94 | va_list args; 95 | va_start(args, fmt); 96 | vprintf(fmt, args); 97 | va_end(args); 98 | 99 | if (perr) { 100 | printf(": %s", strerr); 101 | } 102 | 103 | if (log_isStdioTTY) { 104 | printf("\033[0m"); 105 | } 106 | 107 | printf("\n"); 108 | fflush(stdout); 109 | } 110 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DEX Repair 4 | ----------------------------------------- 5 | 6 | Anestis Bechtsoudis 7 | Copyright 2015-2016 by CENSUS S.A. All Rights Reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "common.h" 30 | #include "utils.h" 31 | #include "log.h" 32 | 33 | static bool utils_readdir(infiles_t *pFiles) 34 | { 35 | DIR *dir = opendir(pFiles->inputFile); 36 | if (!dir) { 37 | LOGMSG_P(l_ERROR, "Couldn't open dir '%s'", pFiles->inputFile); 38 | return false; 39 | } 40 | 41 | size_t count = 0; 42 | for (;;) { 43 | errno = 0; 44 | struct dirent *entry = readdir(dir); 45 | if (entry == NULL && errno == EINTR) { 46 | continue; 47 | } 48 | if (entry == NULL && errno != 0) { 49 | LOGMSG_P(l_ERROR, "readdir('%s')", pFiles->inputFile); 50 | return false; 51 | } 52 | if (entry == NULL) { 53 | break; 54 | } 55 | 56 | char path[PATH_MAX]; 57 | snprintf(path, sizeof(path), "%s/%s", pFiles->inputFile, entry->d_name); 58 | 59 | struct stat st; 60 | if (stat(path, &st) == -1) { 61 | LOGMSG(l_WARN, "Couldn't stat() the '%s' file", path); 62 | continue; 63 | } 64 | 65 | if (!S_ISREG(st.st_mode)) { 66 | LOGMSG(l_DEBUG, "'%s' is not a regular file, skipping", path); 67 | continue; 68 | } 69 | 70 | if (st.st_size == 0) { 71 | LOGMSG(l_DEBUG, "'%s' is empty", path); 72 | continue; 73 | } 74 | 75 | if (!(pFiles->files = realloc(pFiles->files, sizeof(char *) * (count + 1)))) { 76 | LOGMSG_P(l_ERROR, "Couldn't allocate memory"); 77 | closedir(dir); 78 | return false; 79 | } 80 | 81 | pFiles->files[count] = strdup(path); 82 | if (!pFiles->files[count]) { 83 | LOGMSG_P(l_ERROR, "Couldn't allocate memory"); 84 | closedir(dir); 85 | return false; 86 | } 87 | pFiles->fileCnt = ++count; 88 | 89 | LOGMSG(l_DEBUG, "Added '%s' to the list of input files", path); 90 | } 91 | 92 | closedir(dir); 93 | if (count == 0) { 94 | LOGMSG(l_ERROR, "Directory '%s' doesn't contain any regular files", pFiles->inputFile); 95 | return false; 96 | } 97 | 98 | LOGMSG(l_INFO, "%u input files have been added to the list", pFiles->fileCnt); 99 | return true; 100 | } 101 | 102 | bool utils_init(infiles_t *pFiles) 103 | { 104 | pFiles->files = malloc(sizeof(char *)); 105 | if (!pFiles->files) { 106 | LOGMSG_P(l_ERROR, "Couldn't allocate memory"); 107 | return false; 108 | } 109 | 110 | if (!pFiles->inputFile) { 111 | LOGMSG(l_ERROR, "No input file/dir specified"); 112 | return false; 113 | } 114 | 115 | struct stat st; 116 | if (stat(pFiles->inputFile, &st) == -1) { 117 | LOGMSG_P(l_ERROR, "Couldn't stat the input file/dir '%s'", 118 | pFiles->inputFile); 119 | return false; 120 | } 121 | 122 | if (S_ISDIR(st.st_mode)) { 123 | return utils_readdir(pFiles); 124 | } 125 | 126 | if (!S_ISREG(st.st_mode)) { 127 | LOGMSG(l_ERROR, "'%s' is not a regular file, nor a directory", 128 | pFiles->inputFile); 129 | return false; 130 | } 131 | 132 | pFiles->files[0] = pFiles->inputFile; 133 | pFiles->fileCnt = 1; 134 | 135 | return true; 136 | } 137 | 138 | bool utils_writeToFd(int fd, uint8_t *buf, off_t fileSz) 139 | { 140 | off_t written = 0; 141 | while (written < fileSz) { 142 | ssize_t sz = write(fd, &buf[written], fileSz - written); 143 | if (sz < 0 && errno == EINTR) 144 | continue; 145 | 146 | if (sz < 0) 147 | return false; 148 | 149 | written += sz; 150 | } 151 | 152 | return true; 153 | } 154 | 155 | uint8_t* utils_mapFileToRead(char *fileName, off_t *fileSz, int *fd) 156 | { 157 | if ((*fd = open(fileName, O_RDONLY)) == -1) { 158 | LOGMSG_P(l_WARN, "Couldn't open() '%s' file in R/O mode", fileName); 159 | return NULL; 160 | } 161 | 162 | struct stat st; 163 | if (fstat(*fd, &st) == -1) { 164 | LOGMSG_P(l_WARN, "Couldn't stat() the '%s' file", fileName); 165 | close(*fd); 166 | return NULL; 167 | } 168 | 169 | uint8_t *buf; 170 | if ((buf = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 171 | *fd, 0)) == MAP_FAILED) { 172 | LOGMSG_P(l_WARN, "Couldn't mmap() the '%s' file", fileName); 173 | close(*fd); 174 | return NULL; 175 | } 176 | 177 | *fileSz = st.st_size; 178 | return buf; 179 | } 180 | -------------------------------------------------------------------------------- /src/dexRepair.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DEX Repair 4 | ----------------------------------------- 5 | 6 | Anestis Bechtsoudis 7 | Copyright 2015-2017 by CENSUS S.A. All Rights Reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "common.h" 29 | #include "log.h" 30 | #include "utils.h" 31 | #include "dex.h" 32 | 33 | /* Module global variables */ 34 | static int logLevel = l_INFO; 35 | 36 | /* Help page */ 37 | static void usage(bool exit_success) 38 | { 39 | printf("%s", 40 | " " AB "-I, --input-files=DIR" AC " : " 41 | "input files dirs (1 level recursion only) or single file\n" 42 | " " AB "-S, --repair-sha" AC " : " 43 | "repair SHA-1 hash too (default: disabled)\n" 44 | " " AB "-h, --help" AC " : " 45 | "this help\n" 46 | " " AB "-v, --debug=LEVEL" AC " : " 47 | "debug level (0 - FATAL ... 4 - DEBUG), default: '" AB "3" AC "' (INFO)\n" 48 | ); 49 | 50 | if (exit_success) exit(EXIT_SUCCESS); 51 | else exit(EXIT_FAILURE); 52 | } 53 | 54 | int main(int argc, char **argv) 55 | { 56 | int c; 57 | bool repairSHA = false; 58 | 59 | /* Default values */ 60 | infiles_t pFiles = { 61 | .inputFile = NULL, 62 | .files = NULL, 63 | .fileCnt = 0, 64 | }; 65 | 66 | printf("\t\t"AB PROG_NAME" ver. "PROG_VERSION"\n\n"PROG_AUTHORS AC "\n\n"); 67 | if (argc < 1) usage(true); 68 | 69 | struct option longopts[] = { 70 | {"input-files", required_argument, 0, 'I'}, 71 | {"repair-sha", no_argument, 0, 'S'}, 72 | {"help", no_argument, 0, 'h'}, 73 | {"debug", required_argument, 0, 'v'}, 74 | {0, 0, 0, 0 } 75 | }; 76 | 77 | while (( c = getopt_long(argc, argv, "I:hv:S", longopts, NULL)) != -1) { 78 | switch (c) { 79 | case 'I': 80 | pFiles.inputFile = optarg; 81 | break; 82 | case 'S': 83 | repairSHA = true; 84 | break; 85 | case 'h': 86 | usage(true); 87 | break; 88 | case 'v': 89 | logLevel = atoi(optarg); 90 | break; 91 | default: 92 | break; 93 | } 94 | } 95 | 96 | /* adjust log level */ 97 | log_setMinLevel(logLevel); 98 | 99 | /* initialize input files */ 100 | if (!utils_init(&pFiles)) { 101 | LOGMSG(l_FATAL, "Couldn't load input files"); 102 | exit(EXIT_FAILURE); 103 | } 104 | 105 | size_t repairedCnt = 0; 106 | 107 | for (size_t f = 0; f < pFiles.fileCnt; f++) { 108 | off_t fileSz = 0; 109 | int srcfd = -1, dstfd = -1; 110 | uint8_t *buf = NULL; 111 | 112 | LOGMSG(l_DEBUG, "Repairing '%s'", pFiles.files[f]); 113 | 114 | /* mmap file */ 115 | buf = utils_mapFileToRead(pFiles.files[f], &fileSz, &srcfd); 116 | if (buf == NULL) { 117 | LOGMSG(l_ERROR, "open & map failed for R/O mode. Skipping '%s'", 118 | pFiles.files[f]); 119 | continue; 120 | } 121 | 122 | if ((size_t)fileSz < sizeof(dexHeader)) { 123 | LOGMSG(l_WARN, "Invalid input file. Skipping '%s'", 124 | pFiles.files[f]); 125 | munmap(buf, fileSz); 126 | close(srcfd); 127 | continue; 128 | } 129 | 130 | const dexHeader *pDexHeader = (const dexHeader*)buf; 131 | 132 | /* Validate DEX magic number */ 133 | if (!dex_isValidDexMagic(pDexHeader)) { 134 | LOGMSG(l_WARN, "Invalid magic number. Skipping '%s'", 135 | pFiles.files[f]); 136 | munmap(buf, fileSz); 137 | close(srcfd); 138 | continue; 139 | } 140 | 141 | /* First repair SHA-1 if enabled */ 142 | if (repairSHA) { 143 | if(!dex_repairDexSHA1(buf, fileSz)) { 144 | LOGMSG(l_ERROR, "Failed to repair SHA-1 hash from '%s' - skipping", 145 | pFiles.files[f]); 146 | continue; 147 | } 148 | } 149 | 150 | /* Finally repair CRC */ 151 | dex_repairDexCRC(buf, fileSz); 152 | 153 | char outFile[NAME_MAX] = { 0 }; 154 | snprintf(outFile, NAME_MAX, "%s_repaired.dex", pFiles.files[f]); 155 | 156 | /* Write repaired file */ 157 | dstfd = open(outFile, O_CREAT | O_EXCL | O_RDWR, 0644); 158 | if (dstfd == -1) { 159 | LOGMSG_P(l_ERROR, "Couldn't create output file '%s' in " 160 | "input directory", outFile); 161 | munmap(buf, fileSz); 162 | close(srcfd); 163 | continue; 164 | } 165 | 166 | if (!utils_writeToFd(dstfd, buf, fileSz)) { 167 | munmap(buf, fileSz); 168 | close(srcfd); 169 | close(dstfd); 170 | LOGMSG(l_WARN, "Skipping '%s'", pFiles.files[f]); 171 | continue; 172 | } 173 | 174 | repairedCnt++; 175 | 176 | /* Clean-up */ 177 | munmap(buf, fileSz); 178 | buf = NULL; 179 | close(srcfd); 180 | close(dstfd); 181 | } 182 | 183 | LOGMSG(l_INFO, "%u our of %u files have been successfully repaired", 184 | repairedCnt, pFiles.fileCnt); 185 | LOGMSG(l_INFO, "Repaired DEX files available at '%s'", pFiles.inputFile); 186 | 187 | return EXIT_SUCCESS; 188 | } 189 | -------------------------------------------------------------------------------- /src/dex.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | DEX Repair 4 | ----------------------------------------- 5 | 6 | Anestis Bechtsoudis 7 | Copyright 2015-2016 by CENSUS S.A. All Rights Reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | */ 22 | 23 | #ifndef _DEX_H_ 24 | #define _DEX_H_ 25 | 26 | #include 27 | #include "sha1.h" 28 | 29 | typedef uint8_t u1; 30 | typedef uint16_t u2; 31 | typedef uint32_t u4; 32 | typedef uint64_t u8; 33 | typedef int8_t s1; 34 | typedef int16_t s2; 35 | typedef int32_t s4; 36 | typedef int64_t s8; 37 | 38 | #define kNumDexVersions 4 39 | #define kDexVersionLen 4 40 | #define kSHA1Len SHA1HashSize 41 | 42 | static const uint8_t kDexMagic[] = { 'd', 'e', 'x', '\n' }; 43 | static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen] = { 44 | { '0', '3', '5', '\0' }, 45 | // Dex version 036 skipped 46 | { '0', '3', '7', '\0' }, 47 | // Dex version 038: Android "O". 48 | { '0', '3', '8', '\0' }, 49 | // Dex verion 039: Beyond Android "O". 50 | { '0', '3', '9', '\0' }, 51 | }; 52 | 53 | typedef struct __attribute__((packed)) { 54 | char dex[3]; 55 | char nl[1]; 56 | char ver[3]; 57 | char zero[1]; 58 | } dexMagic; 59 | 60 | typedef struct __attribute__((packed)) { 61 | dexMagic magic; 62 | u4 checksum; 63 | unsigned char signature[kSHA1Len]; 64 | u4 fileSize; 65 | u4 headerSize; 66 | u4 endianTag; 67 | u4 linkSize; 68 | u4 linkOff; 69 | u4 mapOff; 70 | u4 stringIdsSize; 71 | u4 stringIdsOff; 72 | u4 typeIdsSize; 73 | u4 typeIdsOff; 74 | u4 protoIdsSize; 75 | u4 protoIdsOff; 76 | u4 fieldIdsSize; 77 | u4 fieldIdsOff; 78 | u4 methodIdsSize; 79 | u4 methodIdsOff; 80 | u4 classDefsSize; 81 | u4 classDefsOff; 82 | u4 dataSize; 83 | u4 dataOff; 84 | } dexHeader; 85 | 86 | typedef struct __attribute__((packed)) { 87 | dexMagic magic; 88 | u4 dexOff; 89 | u4 dexSize; 90 | u4 depsOff; 91 | u4 depsSize; 92 | u4 optOff; 93 | u4 optSize; 94 | u4 flags; 95 | u4 checksum; 96 | } odexHeader; 97 | 98 | typedef struct __attribute__((packed)) { 99 | u4 stringDataOff; 100 | } dexStringId; 101 | 102 | typedef struct __attribute__((packed)) { 103 | u4 descriptorIdx; 104 | } dexTypeId; 105 | 106 | typedef struct __attribute__((packed)) { 107 | u2 classIdx; 108 | u2 typeIdx; 109 | u4 nameIdx; 110 | } dexFieldId; 111 | 112 | typedef struct __attribute__((packed)) { 113 | u2 classIdx; 114 | u2 protoIdx; 115 | u4 nameIdx; 116 | } dexMethodId; 117 | 118 | typedef struct __attribute__((packed)) { 119 | u4 shortyIdx; 120 | u4 returnTypeIdx; 121 | u4 parametersOff; 122 | } dexProtoId; 123 | 124 | typedef struct __attribute__((packed)) { 125 | u4 classIdx; 126 | u4 accessFlags; 127 | u4 superclassOdx; 128 | u4 interfacesOff; 129 | u4 sourceFileIdx; 130 | u4 annotationsOff; 131 | u4 classDataOff; 132 | u4 staticValuesOff; 133 | } dexClassDef; 134 | 135 | typedef struct __attribute__((packed)) { 136 | u2 typeIdx; 137 | } dexTypeItem; 138 | 139 | typedef struct __attribute__((packed)) { 140 | u4 size; 141 | dexTypeItem list[1]; 142 | } dexTypeList; 143 | 144 | typedef struct __attribute__((packed)) { 145 | u2 type; 146 | u2 unused; 147 | u4 size; 148 | u4 offset; 149 | } dexMapItem; 150 | 151 | typedef struct __attribute__((packed)) { 152 | u4 size; 153 | dexMapItem list[1]; 154 | } dexMapList; 155 | 156 | typedef struct __attribute__((packed)) { 157 | u2 registersSize; 158 | u2 insSize; 159 | u2 outsSize; 160 | u2 tries_size; 161 | u4 debug_info_off; 162 | u4 insns_size; 163 | u2 insns[1]; 164 | /* followed by optional u2 padding */ 165 | /* followed by try_item[triesSize] */ 166 | /* followed by uleb128 handlersSize */ 167 | /* followed by catch_handler_item[handlersSize] */ 168 | } dexCode; 169 | 170 | typedef struct __attribute__((packed)) { 171 | u4 start_addr_; 172 | u2 insn_count_; 173 | u2 handler_off_; 174 | } dexTryItem; 175 | 176 | typedef struct __attribute__((packed)) { 177 | u1 bleargh; 178 | } dexLinkData; 179 | 180 | typedef struct __attribute__((packed)) { 181 | int size; 182 | int numEntries; 183 | struct { 184 | u4 classDescriptorHash; 185 | int classDescriptorOff; 186 | int classDefOff; 187 | } table[1]; 188 | } dexClassLookup; 189 | 190 | typedef struct __attribute__((packed)) { 191 | odexHeader *pOdexHeader; 192 | dexHeader *pDexHeader; 193 | dexStringId *pDexStringIds; 194 | dexTypeId *pDexTypeIds; 195 | dexFieldId *pDexFieldIds; 196 | dexMethodId *pDexMethodIds; 197 | dexProtoId *pDexProtoIds; 198 | dexClassDef *pDexClassDefs; 199 | dexLinkData *pDexLinkData; 200 | dexClassLookup *pclassLookup; 201 | void *pregisterMapPool; 202 | u1 *baseAddr; 203 | int overhead; 204 | //void* auxData; 205 | } dexFile; 206 | 207 | typedef struct __attribute__((packed)) { 208 | u4 staticFieldsSize; 209 | u4 instanceFieldsSize; 210 | u4 directMethodsSize; 211 | u4 virtualMethodsSize; 212 | } dexClassDataHeader; 213 | 214 | typedef struct __attribute__((packed)) { 215 | u4 methodIdx; 216 | u4 accessFlags; 217 | u4 codeOff; 218 | } dexMethod; 219 | 220 | typedef struct __attribute__((packed)) { 221 | u4 fieldIdx; 222 | u4 accessFlags; 223 | } dexField; 224 | 225 | typedef struct __attribute__((packed)) { 226 | dexClassDataHeader header; 227 | dexField *staticFields; 228 | dexField *instanceFields; 229 | dexMethod *directMethods; 230 | dexMethod *virtualMethods; 231 | } dexClassData; 232 | 233 | /* 234 | * Verify if valid DEX file magic number 235 | */ 236 | bool dex_isValidDexMagic(const dexHeader *pDexHeader) 237 | { 238 | /* Validate magic number */ 239 | if (memcmp(pDexHeader->magic.dex, kDexMagic, sizeof(kDexMagic)) != 0) { 240 | return false; 241 | } 242 | 243 | /* Validate magic version */ 244 | const char *version = pDexHeader->magic.ver; 245 | for (uint32_t i = 0; i < kNumDexVersions; i++) { 246 | if (memcmp(version, kDexMagicVersions[i], kDexVersionLen) == 0) { 247 | LOGMSG(l_DEBUG, "DEX version '%s' detected", pDexHeader->magic.ver); 248 | return true; 249 | } 250 | } 251 | return false; 252 | } 253 | 254 | /* 255 | * Repair DEX file CRC 256 | */ 257 | void dex_repairDexCRC(uint8_t *buf, off_t fileSz) 258 | { 259 | /* Repair DEX CRC */ 260 | uint32_t adler_checksum = adler32(0L, Z_NULL, 0); 261 | const uint8_t non_sum = sizeof(dexMagic) + sizeof(uint32_t); 262 | const uint8_t *non_sum_ptr = (const uint8_t*)buf + non_sum; 263 | adler_checksum = adler32(adler_checksum, non_sum_ptr, fileSz - non_sum); 264 | memcpy(buf + sizeof(dexMagic), &adler_checksum, sizeof(uint32_t)); 265 | } 266 | 267 | /* 268 | * Repair DEX file SHA-1 269 | */ 270 | bool dex_repairDexSHA1(uint8_t *buf, off_t fileSz) 271 | { 272 | const uint8_t sha1_off = sizeof(dexMagic) + sizeof(uint32_t); 273 | const uint8_t non_sha1_off = sizeof(dexMagic) + sizeof(uint32_t) + (kSHA1Len * sizeof(char)); 274 | const uint8_t *non_sha1_ptr = (const uint8_t*)buf + non_sha1_off; 275 | 276 | SHA1Context sha; 277 | if (SHA1Reset(&sha)) { 278 | return false; 279 | } 280 | 281 | if (SHA1Input(&sha, non_sha1_ptr, fileSz - non_sha1_off)) { 282 | return false; 283 | } 284 | 285 | if (SHA1Result(&sha, buf + sha1_off)) { 286 | return false; 287 | } 288 | 289 | return true; 290 | } 291 | 292 | #endif 293 | -------------------------------------------------------------------------------- /src/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.c 3 | * 4 | * Description: 5 | * This file implements the Secure Hashing Algorithm 1 as 6 | * defined in FIPS PUB 180-1 published April 17, 1995. 7 | * 8 | * The SHA-1, produces a 160-bit message digest for a given 9 | * data stream. It should take about 2**n steps to find a 10 | * message with the same digest as a given message and 11 | * 2**(n/2) to find any two messages with the same digest, 12 | * when n is the digest size in bits. Therefore, this 13 | * algorithm can serve as a means of providing a 14 | * "fingerprint" for a message. 15 | * 16 | * Portability Issues: 17 | * SHA-1 is defined in terms of 32-bit "words". This code 18 | * uses (included via "sha1.h" to define 32 and 8 19 | * bit unsigned integer types. If your C compiler does not 20 | * support 32 bit unsigned integers, this code is not 21 | * appropriate. 22 | * 23 | * Caveats: 24 | * SHA-1 is designed to work with messages less than 2^64 bits 25 | * long. Although SHA-1 allows a message digest to be generated 26 | * for messages of any number of bits less than 2^64, this 27 | * implementation only works with messages with a length that is 28 | * a multiple of the size of an 8-bit character. 29 | * 30 | */ 31 | 32 | #include "sha1.h" 33 | 34 | /* 35 | * Define the SHA1 circular left shift macro 36 | */ 37 | #define SHA1CircularShift(bits,word) \ 38 | (((word) << (bits)) | ((word) >> (32-(bits)))) 39 | 40 | /* Local Function Prototyptes */ 41 | void SHA1PadMessage(SHA1Context *); 42 | void SHA1ProcessMessageBlock(SHA1Context *); 43 | 44 | /* 45 | * SHA1Reset 46 | * 47 | * Description: 48 | * This function will initialize the SHA1Context in preparation 49 | * for computing a new SHA1 message digest. 50 | * 51 | * Parameters: 52 | * context: [in/out] 53 | * The context to reset. 54 | * 55 | * Returns: 56 | * sha Error Code. 57 | * 58 | */ 59 | int SHA1Reset(SHA1Context *context) 60 | { 61 | if (!context) 62 | { 63 | return shaNull; 64 | } 65 | 66 | context->Length_Low = 0; 67 | context->Length_High = 0; 68 | context->Message_Block_Index = 0; 69 | 70 | context->Intermediate_Hash[0] = 0x67452301; 71 | context->Intermediate_Hash[1] = 0xEFCDAB89; 72 | context->Intermediate_Hash[2] = 0x98BADCFE; 73 | context->Intermediate_Hash[3] = 0x10325476; 74 | context->Intermediate_Hash[4] = 0xC3D2E1F0; 75 | 76 | context->Computed = 0; 77 | context->Corrupted = 0; 78 | 79 | return shaSuccess; 80 | } 81 | 82 | /* 83 | * SHA1Result 84 | * 85 | * Description: 86 | * This function will return the 160-bit message digest into the 87 | * Message_Digest array provided by the caller. 88 | * NOTE: The first octet of hash is stored in the 0th element, 89 | * the last octet of hash in the 19th element. 90 | * 91 | * Parameters: 92 | * context: [in/out] 93 | * The context to use to calculate the SHA-1 hash. 94 | * Message_Digest: [out] 95 | * Where the digest is returned. 96 | * 97 | * Returns: 98 | * sha Error Code. 99 | * 100 | */ 101 | int SHA1Result( SHA1Context *context, 102 | uint8_t Message_Digest[SHA1HashSize]) 103 | { 104 | int i; 105 | 106 | if (!context || !Message_Digest) 107 | { 108 | return shaNull; 109 | } 110 | 111 | if (context->Corrupted) 112 | { 113 | return context->Corrupted; 114 | } 115 | 116 | if (!context->Computed) 117 | { 118 | SHA1PadMessage(context); 119 | for(i=0; i<64; ++i) 120 | { 121 | /* message may be sensitive, clear it out */ 122 | context->Message_Block[i] = 0; 123 | } 124 | context->Length_Low = 0; /* and clear length */ 125 | context->Length_High = 0; 126 | context->Computed = 1; 127 | 128 | } 129 | 130 | for(i = 0; i < SHA1HashSize; ++i) 131 | { 132 | Message_Digest[i] = context->Intermediate_Hash[i>>2] 133 | >> 8 * ( 3 - ( i & 0x03 ) ); 134 | } 135 | 136 | return shaSuccess; 137 | } 138 | 139 | /* 140 | * SHA1Input 141 | * 142 | * Description: 143 | * This function accepts an array of octets as the next portion 144 | * of the message. 145 | * 146 | * Parameters: 147 | * context: [in/out] 148 | * The SHA context to update 149 | * message_array: [in] 150 | * An array of characters representing the next portion of 151 | * the message. 152 | * length: [in] 153 | * The length of the message in message_array 154 | * 155 | * Returns: 156 | * sha Error Code. 157 | * 158 | */ 159 | int SHA1Input( SHA1Context *context, 160 | const uint8_t *message_array, 161 | unsigned length) 162 | { 163 | if (!length) 164 | { 165 | return shaSuccess; 166 | } 167 | 168 | if (!context || !message_array) 169 | { 170 | return shaNull; 171 | } 172 | 173 | if (context->Computed) 174 | { 175 | context->Corrupted = shaStateError; 176 | 177 | return shaStateError; 178 | } 179 | 180 | if (context->Corrupted) 181 | { 182 | return context->Corrupted; 183 | } 184 | while(length-- && !context->Corrupted) 185 | { 186 | context->Message_Block[context->Message_Block_Index++] = 187 | (*message_array & 0xFF); 188 | 189 | context->Length_Low += 8; 190 | if (context->Length_Low == 0) 191 | { 192 | context->Length_High++; 193 | if (context->Length_High == 0) 194 | { 195 | /* Message is too long */ 196 | context->Corrupted = 1; 197 | } 198 | } 199 | 200 | if (context->Message_Block_Index == 64) 201 | { 202 | SHA1ProcessMessageBlock(context); 203 | } 204 | 205 | message_array++; 206 | } 207 | 208 | return shaSuccess; 209 | } 210 | 211 | /* 212 | * SHA1ProcessMessageBlock 213 | * 214 | * Description: 215 | * This function will process the next 512 bits of the message 216 | * stored in the Message_Block array. 217 | * 218 | * Parameters: 219 | * None. 220 | * 221 | * Returns: 222 | * Nothing. 223 | * 224 | * Comments: 225 | 226 | * Many of the variable names in this code, especially the 227 | * single character names, were used because those were the 228 | * names used in the publication. 229 | * 230 | * 231 | */ 232 | void SHA1ProcessMessageBlock(SHA1Context *context) 233 | { 234 | const uint32_t K[] = { /* Constants defined in SHA-1 */ 235 | 0x5A827999, 236 | 0x6ED9EBA1, 237 | 0x8F1BBCDC, 238 | 0xCA62C1D6 239 | }; 240 | int t; /* Loop counter */ 241 | uint32_t temp; /* Temporary word value */ 242 | uint32_t W[80]; /* Word sequence */ 243 | uint32_t A, B, C, D, E; /* Word buffers */ 244 | 245 | /* 246 | * Initialize the first 16 words in the array W 247 | */ 248 | for(t = 0; t < 16; t++) 249 | { 250 | W[t] = context->Message_Block[t * 4] << 24; 251 | W[t] |= context->Message_Block[t * 4 + 1] << 16; 252 | W[t] |= context->Message_Block[t * 4 + 2] << 8; 253 | W[t] |= context->Message_Block[t * 4 + 3]; 254 | } 255 | 256 | for(t = 16; t < 80; t++) 257 | { 258 | W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 259 | } 260 | 261 | A = context->Intermediate_Hash[0]; 262 | B = context->Intermediate_Hash[1]; 263 | C = context->Intermediate_Hash[2]; 264 | D = context->Intermediate_Hash[3]; 265 | E = context->Intermediate_Hash[4]; 266 | 267 | for(t = 0; t < 20; t++) 268 | { 269 | temp = SHA1CircularShift(5,A) + 270 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 271 | E = D; 272 | D = C; 273 | C = SHA1CircularShift(30,B); 274 | 275 | B = A; 276 | A = temp; 277 | } 278 | 279 | for(t = 20; t < 40; t++) 280 | { 281 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; 282 | E = D; 283 | D = C; 284 | C = SHA1CircularShift(30,B); 285 | B = A; 286 | A = temp; 287 | } 288 | 289 | for(t = 40; t < 60; t++) 290 | { 291 | temp = SHA1CircularShift(5,A) + 292 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 293 | E = D; 294 | D = C; 295 | C = SHA1CircularShift(30,B); 296 | B = A; 297 | A = temp; 298 | } 299 | 300 | for(t = 60; t < 80; t++) 301 | { 302 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; 303 | E = D; 304 | D = C; 305 | C = SHA1CircularShift(30,B); 306 | B = A; 307 | A = temp; 308 | } 309 | 310 | context->Intermediate_Hash[0] += A; 311 | context->Intermediate_Hash[1] += B; 312 | context->Intermediate_Hash[2] += C; 313 | context->Intermediate_Hash[3] += D; 314 | context->Intermediate_Hash[4] += E; 315 | 316 | context->Message_Block_Index = 0; 317 | } 318 | 319 | /* 320 | * SHA1PadMessage 321 | * 322 | 323 | * Description: 324 | * According to the standard, the message must be padded to an even 325 | * 512 bits. The first padding bit must be a '1'. The last 64 326 | * bits represent the length of the original message. All bits in 327 | * between should be 0. This function will pad the message 328 | * according to those rules by filling the Message_Block array 329 | * accordingly. It will also call the ProcessMessageBlock function 330 | * provided appropriately. When it returns, it can be assumed that 331 | * the message digest has been computed. 332 | * 333 | * Parameters: 334 | * context: [in/out] 335 | * The context to pad 336 | * ProcessMessageBlock: [in] 337 | * The appropriate SHA*ProcessMessageBlock function 338 | * Returns: 339 | * Nothing. 340 | * 341 | */ 342 | 343 | void SHA1PadMessage(SHA1Context *context) 344 | { 345 | /* 346 | * Check to see if the current message block is too small to hold 347 | * the initial padding bits and length. If so, we will pad the 348 | * block, process it, and then continue padding into a second 349 | * block. 350 | */ 351 | if (context->Message_Block_Index > 55) 352 | { 353 | context->Message_Block[context->Message_Block_Index++] = 0x80; 354 | while(context->Message_Block_Index < 64) 355 | { 356 | context->Message_Block[context->Message_Block_Index++] = 0; 357 | } 358 | 359 | SHA1ProcessMessageBlock(context); 360 | 361 | while(context->Message_Block_Index < 56) 362 | { 363 | context->Message_Block[context->Message_Block_Index++] = 0; 364 | } 365 | } 366 | else 367 | { 368 | context->Message_Block[context->Message_Block_Index++] = 0x80; 369 | while(context->Message_Block_Index < 56) 370 | { 371 | 372 | context->Message_Block[context->Message_Block_Index++] = 0; 373 | } 374 | } 375 | 376 | /* 377 | * Store the message length as the last 8 octets 378 | */ 379 | context->Message_Block[56] = context->Length_High >> 24; 380 | context->Message_Block[57] = context->Length_High >> 16; 381 | context->Message_Block[58] = context->Length_High >> 8; 382 | context->Message_Block[59] = context->Length_High; 383 | context->Message_Block[60] = context->Length_Low >> 24; 384 | context->Message_Block[61] = context->Length_Low >> 16; 385 | context->Message_Block[62] = context->Length_Low >> 8; 386 | context->Message_Block[63] = context->Length_Low; 387 | 388 | SHA1ProcessMessageBlock(context); 389 | } 390 | --------------------------------------------------------------------------------