#include "main.hpp" void patch_class_name(FILE *fp, char *name, unsigned short len, unsigned short offset, unsigned short size) { // Переведём имя в верхний регистр for (unsigned short i = 0; i < size; ++i) name[offset + i] = toupper(name[offset + i]); fseek(fp, ftell(fp) - (len - offset), SEEK_SET); fwrite(name + offset, 1, size, fp); if (offset) fseek(fp, ftell(fp) + offset, SEEK_SET); } int process_string_constant(FILE *fp, char *name, unsigned short len) { char *p; if (len == sizeof("platformRequest") - 1 && strcmp(name, "platformRequest") == 0) { // Nothing todo... return CONST_HACK_KEYWORD; } else if ((p = strstr(name, MESSAGE_CONNECTION))) { patch_class_name(fp, name, len, p - name, sizeof(MESSAGE_CONNECTION) - 1); return (CONST_HACK_REPLACED | CONST_HACK_KEYWORD); } else if ((p = strstr(name, TEXT_MESSAGE))) { patch_class_name(fp, name, len, p - name, sizeof(TEXT_MESSAGE) - 1); return (CONST_HACK_REPLACED | CONST_HACK_KEYWORD); } else if ((p = strstr(name, MIDLET))) { patch_class_name(fp, name, len, p - name, sizeof(MIDLET) - 1); return CONST_HACK_REPLACED; } return CONST_HACK_NONE; } int hack_class(FILE *fp, bool *need_repack, bool *class_changed) { unsigned int magic_number; unsigned short minor_version, major_version, constant_count; // Прочитаем header класса if ( !read_int(&magic_number, fp) || !read_short(&minor_version, fp) || !read_short(&major_version, fp) || !read_short(&constant_count, fp) ) { fprintf(stderr, "Can't read class header: %s\n", strerror(errno)); return E_IO_ERROR; } // Проверим MAGIC if (magic_number != 0xCAFEBABE) { fprintf(stderr, "Invalid magic! Is not class!\n"); return E_CLASS_MAGIC; } // Парсим Constant Pool int ret; unsigned char cp_type = 0; for (unsigned short i = 0; i < constant_count - 1; ++i) { if (!read_byte(&cp_type, fp) == 1) { fprintf(stderr, "Can't read const type: %s\n", strerror(errno)); return E_IO_ERROR; } switch (cp_type) { // Пропустим 2 байта case CONST_CLASS: case CONST_STRING: fseek(fp, ftell(fp) + 2, SEEK_SET); break; // Пропустим 4 байта case CONST_FIELD_REF: case CONST_METHOD_REF: case CONST_INTERFACE_METHOD_REF: case CONST_INTEGER: case CONST_FLOAT: case CONST_NAME_AND_TYPE: fseek(fp, ftell(fp) + 4, SEEK_SET); break; // Пропустим 8 байт case CONST_LONG: case CONST_DOUBLE: fseek(fp, ftell(fp) + 8, SEEK_SET); break; // Строки. То, что нам нужно. case CONST_UTF8: { unsigned short len = 0; char *value; if (read_short(&len, fp)) { value = new char[len + 1]; if (fread(value, 1, len, fp) == len) { value[len] = 0; // printf("CONST_UTF8 [%d] = \"%s\"\n", len, value); ret = process_string_constant(fp, value, len); if ((ret & CONST_HACK_REPLACED) && !*class_changed) *class_changed = true; if ((ret & CONST_HACK_KEYWORD) && !*need_repack) *need_repack = true; delete[] value; } else { delete[] value; fprintf(stderr, "Can't read string data!\n"); return -1; } } else { fprintf(stderr, "Can't read string length!\n"); return -1; } } break; default: fprintf(stderr, "Unknown constant type %04X!!!\n", cp_type); // Ебанитовые обфускаторы или компиляторы любят пихать сюда разную хуитку // Поэтому не будем падать. А только ругаться. // return E_UNKNOWN_CONST_TYPE; break; } } return E_OK; } bool zip_add_files_from_dir(zip *zip, const char *dir_path, unsigned int offset = 0) { struct dirent *file; bool state = true; DIR *dir = opendir(dir_path); char path[PATH_MAX]; struct stat tmp_stat; struct zip_stat zstat; if (dir) { while ((file = readdir(dir))) { if (!strcmp(".", file -> d_name) || !strcmp("..", file -> d_name)) continue; snprintf(path, PATH_MAX, "%s/%s", dir_path, file -> d_name); if (stat(path, &tmp_stat) != 0) { fprintf(stderr, "Can't stat(%s): %s\n", path, strerror(errno)); continue; } // Если уже существует bool need_create = true; if (zip_stat(zip, path + offset, 0, &zstat) == 0) { if ( // Если в архиве папка, но добавляемый объект не папка (zstat.crc == 0 && zstat.size == 0 && !S_ISDIR(tmp_stat.st_mode)) || // Если в архиве файл, но добавляемый объект не регулярный файл (zstat.crc != 0 && !S_ISREG(tmp_stat.st_mode)) ) { // Удаляем if (zip_delete(zip, zstat.index) != 0) { fprintf ( stderr, "Can't delete #%ld (%s; %08X; %ld): %s\n", zstat.index, zstat.name, zstat.crc, zstat.size, zip_strerror(zip) ); state = false; break; } } else need_create = false; } if (S_ISDIR(tmp_stat.st_mode)) { if (need_create && zip_add_dir(zip, path + offset) < 0) { fprintf(stderr, "Can't create dir %s: %s\n", path + offset, zip_strerror(zip)); state = false; break; } if (!zip_add_files_from_dir(zip, path, (!offset ? strlen(dir_path) : offset)) && state) { state = false; break; } } else if (S_ISREG(tmp_stat.st_mode)) { zip_source *src = zip_source_file(zip, path, 0, tmp_stat.st_size); if (src) { if (zip_add(zip, path + offset, src) < 0) { fprintf(stderr, "Can't add file %s: %s\n", path, zip_strerror(zip)); state = false; } } else { fprintf(stderr, "Can't source from file %s: %s\n", path, zip_strerror(zip)); state = false; break; } } printf("%s\n", path); } state = true; } else { fprintf(stderr, "Can't open directory (%s): %s\n", dir_path, strerror(errno)); state = false; } return state; } int process_jar_file(const char *filename, const char *tmp_dir_path, const char *bootstrap_dir) { int error = 0, ret; zip *zip = NULL; size_t total, name_len; struct zip_stat zstat; char tmp_file_name[PATH_MAX]; bool need_repack = false; unsigned char buff[FILE_BUFFER_SIZE]; Errors return_value = E_OK; try { zip = zip_open(filename, 0, &error); if (error) { fprintf(stderr, "Can't open jar file %s: %s\n", filename, zip_strerror(zip)); throw E_OPEN_ZIP; } total = zip_get_num_entries(zip, 0); for (size_t i = 0; i < total; ++i) { if (zip_stat_index(zip, i, 0, &zstat) != 0) { fprintf(stderr, "Can't stat file #%ld in %s: %s\n", i, filename, zip_strerror(zip)); throw E_ZIP_STAT_FILE; } // Нам нужны только *.class name_len = strlen(zstat.name); if (name_len < 7 || strcasecmp(zstat.name + (name_len - 6), ".class") != 0) continue; // Запишем .class во временный файл для модификации zip_file *fp = zip_fopen_index(zip, i, 0); if (!fp) { fprintf(stderr, "Can't open file %s (%ld) in %s: %s\n", zstat.name, i, filename, zip_strerror(zip)); throw E_ZIP_OPEN_FILE; } sprintf(tmp_file_name, "%s/class.%08X.%ld.%d", tmp_dir_path, zstat.crc, zstat.index, getpid()); printf("tmp_file_name = %s\n", tmp_file_name); int readed; size_t writed = 0; FILE *fp_tmp = fopen(tmp_file_name, "w+"); if (fp_tmp) { while (writed < zstat.size && (readed = zip_fread(fp, &buff, FILE_BUFFER_SIZE)) != -1) { if (fwrite(buff, 1, readed, fp_tmp) != (size_t)readed) break; // io error writed += readed; } if (writed != zstat.size) { fprintf(stderr, "Can't write data (file: %s): %s\n", tmp_file_name, strerror(ferror(fp_tmp))); fclose(fp_tmp); unlink(tmp_file_name); throw E_IO_ERROR; } } else { fprintf(stderr, "Can't open file %s: %s\n", tmp_file_name, strerror(errno)); throw E_IO_ERROR; } Errors err = E_OK; fseek(fp_tmp, 0, SEEK_SET); bool class_changed = false; // Если похачили класс успешно и он изменён - заменяем его в архиве if ((ret = hack_class(fp_tmp, &need_repack, &class_changed)) == E_OK) { if (class_changed) { printf("%s\n", zstat.name); fseek(fp_tmp, 0, SEEK_SET); zip_source *src = zip_source_file(zip, tmp_file_name, 0, zstat.size); if (src) { if (zip_replace(zip, i, src) != 0) { fprintf(stderr, "Can't update file %s from %s: %s\n", tmp_file_name, filename, zip_strerror(zip)); err = E_ZIP_REPLACE_FILE; } zip_close(zip); } else { fprintf(stderr, "Can't create zip source file: %s\n", zip_strerror(zip)); err = E_ZIP_CREATE_SRC; } } } else { fprintf(stderr, "Can't process class %s from %s (error=%d)\n", zstat.name, filename, ret); // err = E_INVALID_CLASS; // падать из-за одного кривого класса не будем } fclose(fp_tmp); unlink(tmp_file_name); if (err != E_OK) throw err; } // Добавляем наши классы if (need_repack) zip_add_files_from_dir(zip, bootstrap_dir); } catch (Errors err_no) { return_value = err_no; } if (zip) { zip_close(zip); printf("%p\n", zip); zip = NULL; } if (return_value == E_OK && need_repack) return_value = E_OK_CHANGED; return return_value; } int main() { system("cp /home/azq2/проекты/java_antialarm/Midlet.class2 /home/azq2/проекты/java_antialarm/Midlet.class"); system("cp /home/azq2/Загрузки/test2.jar /home/azq2/Загрузки/test.jar"); process_jar_file("/home/azq2/Загрузки/test.jar", "/tmp", "../bootstrap"); return 0; }