#include "../runtime/crypto.h" #include "objects.h" #include "osutils.h" #include "streams.h" #include "files.h" #include "processors.h" #include "inifile.h" #include "script.h" #include "pefile.h" #include "macfile.h" #include "elffile.h" #include "lang.h" #include "core.h" #ifdef __APPLE__ #include #include #include #endif // __APPLE__ #ifdef __unix__ namespace OpenSSL { #include } #endif //__unix__ void Base64ToVector(const char *src, size_t src_len, std::vector &dst) { if (!src || !src_len) { dst.clear(); return; } size_t dst_len = src_len; dst.resize(dst_len, 0); Base64Decode(src, src_len, &dst[0], dst_len); if (dst_len != dst.size()) dst.resize(dst_len); } std::string VectorToBase64(const std::vector &src) { std::string dst; if (!src.empty()) { size_t dst_len = Base64EncodeGetRequiredLength(src.size()); dst.resize(dst_len); Base64Encode(&src[0], src.size(), &dst[0], dst_len); if (dst_len != dst.size()) dst.resize(dst_len); } return dst; } /** * Watermark */ Watermark::Watermark(WatermarkManager *owner) : IObject(), owner_(owner), id_(-1), use_count_(0), enabled_(false) { } Watermark::Watermark(WatermarkManager *owner, const std::string &name, const std::string &value, size_t use_count, bool enabled) : IObject(), owner_(owner), id_(-1), name_(name), value_(value), use_count_(use_count), enabled_(enabled) { Compile(); } Watermark::~Watermark() { if (owner_) owner_->RemoveObject(this); } void Watermark::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } void Watermark::set_name(const std::string &name) { if (name_ != name) { name_ = name; Notify(mtChanged, this); } } void Watermark::set_value(const std::string &value) { if (value_ != value) { value_ = value; Notify(mtChanged, this); } } void Watermark::set_enabled(bool value) { if (enabled_ != value) { enabled_ = value; Notify(mtChanged, this); } } void Watermark::inc_use_count() { use_count_++; Notify(mtChanged, this); } void Watermark::ReadFromIni(IniFile &file, size_t id) { id_ = id; name_ = file.ReadString("Watermarks", string_format("Name%d", id).c_str()); value_ = file.ReadString("Watermarks", string_format("Value%d", id).c_str()); use_count_ = file.ReadInt("Watermarks", string_format("UseCount%d", id).c_str()); enabled_ = file.ReadBool("Watermarks", string_format("Enabled%d", id).c_str(), true); Compile(); } void Watermark::ReadFromNode(TiXmlElement *node) { unsigned int u; u = 0; node->QueryUnsignedAttribute("Id", &u); id_ = u; node->QueryStringAttribute("Name", &name_); u = 0; node->QueryUnsignedAttribute("UseCount", &u); use_count_ = u; enabled_ = true; node->QueryBoolAttribute("Enabled", &enabled_); if (const char *str = node->GetText()) value_ = std::string(str); Compile(); } void Watermark::SaveToNode(TiXmlElement *node) { if (!node) return; node->Clear(); node->SetAttribute("Id", (int)id_); node->SetAttribute("Name", name_); node->SetAttribute("UseCount", (int)use_count_); if (enabled_) node->RemoveAttribute("Enabled"); else node->SetAttribute("Enabled", enabled_); node->LinkEndChild(new TiXmlText(value_)); } void Watermark::SaveToFile(SettingsFile &file) { GlobalLocker locker; if (id_ == NOT_ID) id_ = file.inc_watermark_id(); TiXmlElement *node = file.watermark_node(id_, true); if (node) { SaveToNode(node); file.Save(); } } void Watermark::DeleteFromFile(SettingsFile &file) { TiXmlElement *node = file.watermark_node(id_); if (node && node->Parent()->RemoveChild(node)) file.Save(); } void Watermark::Compile() { dump_.clear(); mask_.clear(); if (value_.size() == 0) return; for (size_t i = 0; i < value_.size(); i++) { size_t p = i / 2; if (p >= dump_.size()) { dump_.push_back(0); mask_.push_back(0); } uint8_t m = 0xff; uint8_t b; char c = value_[i]; if ((c >= '0') && (c <= '9')) { b = c - '0'; } else if ((c >= 'A') && (c <= 'F')) { b = c - 'A' + 0x0a; } else if ((c >= 'a') && (c <= 'f')) { b = c - 'a' + 0x0a; } else { m = 0; b = rand(); } if ((i & 1) == 0) { dump_[p] = (dump_[p] & 0x0f) | (b << 4); mask_[p] = (mask_[p] & 0x0f) | (m << 4); } else { dump_[p] = (dump_[p] & 0xf0) | (b & 0x0f); mask_[p] = (mask_[p] & 0xf0) | (m & 0x0f); } } } bool Watermark::SearchByte(uint8_t value) { if (dump_.size() == 0) return false; bool res = false; for (int i = (int)(pos_.size() - 1); i >= -1; i--) { size_t p = (i == -1) ? 0 : pos_[i]; if ((dump_[p] & mask_[p]) == (value & mask_[p])) { p++; if (p == dump_.size()) { res = true; if (i > -1) pos_.erase(pos_.begin() + i); } else if (i == -1) { pos_.push_back(p); } else { pos_[i] = p; } } else if (i > -1) { pos_.erase(pos_.begin() + i); } } return res; } bool Watermark::AreSimilar(const std::string &v1, const std::string &v2) { // v1 is part of v2 or is vice versa int v1_in_v2_pos = 0, v1_in_v2_pos_max = int(v2.length()) - int(v1.length()); int v2_in_v1_pos = 0, v2_in_v1_pos_max = int(v1.length()) - int(v2.length()); while(v1_in_v2_pos <= v1_in_v2_pos_max) { size_t v1p = 0; for(; v1p < v1.length(); v1p++) { if(!SymbolsMatch(v1[v1p], v2[v1_in_v2_pos + v1p])) break; } if(v1p == v1.length()) return true; v1_in_v2_pos++; } if(v1_in_v2_pos_max == v2_in_v1_pos_max) return false; while(v2_in_v1_pos <= v2_in_v1_pos_max) { size_t v2p = 0; for(; v2p < v2.length(); v2p++) { if(!SymbolsMatch(v2[v2p], v1[v2_in_v1_pos + v2p])) break; } if(v2p == v2.length()) return true; v2_in_v1_pos++; } return false; } bool Watermark::SymbolsMatch(char v1, char v2) { if(v1 == '?' || v2 == '?') return true; assert('a' > 'A'); if(v1 >= 'a') v1 = v1 - 'a' + 'A'; if(v2 >= 'a') v2 = v2 - 'a' + 'A'; return v1 == v2; } /** * WatermarkManager */ WatermarkManager::WatermarkManager(Core *owner) : ObjectList(), owner_(owner) { } Watermark *WatermarkManager::Add(const std::string name, const std::string value, size_t use_count, bool enabled) { Watermark *watermark = new Watermark(this, name, value, use_count, enabled); AddObject(watermark); Notify(mtAdded, watermark); return watermark; } Watermark *WatermarkManager::GetWatermarkByName(const std::string &name) { for (size_t i = 0; i < count(); i++) { Watermark *watermark = item(i); if (watermark->name() == name) return watermark; } return NULL; } void WatermarkManager::InitSearch() const { for (size_t i = 0; i < count(); i++) { item(i)->InitSearch(); } } void WatermarkManager::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } void WatermarkManager::RemoveObject(Watermark *watermark) { Notify(mtDeleted, watermark); ObjectList::RemoveObject(watermark); } void WatermarkManager::ReadFromIni(const std::string &file_name) { IniFile file(file_name.c_str()); std::vector key_list = file.ReadSection("Watermarks", "Name"); for (size_t i = 0; i < key_list.size(); i++) { std::string str = key_list[i]; size_t id = StrToIntDef(&str[4], -1); if (id == NOT_ID) continue; Watermark *watermark = new Watermark(this); watermark->ReadFromIni(file, id); AddObject(watermark); } } void WatermarkManager::ReadFromFile(SettingsFile &file) { TiXmlElement *watermarks_node = file.watermarks_node(); if (!watermarks_node) return; TiXmlElement *node = watermarks_node->FirstChildElement("Watermark"); while (node) { Watermark *watermark = new Watermark(this); watermark->ReadFromNode(node); AddObject(watermark); node = node->NextSiblingElement(node->Value()); } } void WatermarkManager::SaveToFile(SettingsFile &file) { TiXmlElement *watermarks_node = file.watermarks_node(); if (!watermarks_node) return; watermarks_node->Clear(); size_t id = 0; for (size_t i = 0; i < count(); i++) { TiXmlElement *node = new TiXmlElement("Watermark"); watermarks_node->LinkEndChild(node); Watermark *watermark = item(i); watermark->SaveToNode(node); if (id < watermark->id()) id = watermark->id(); } watermarks_node->SetAttribute("Id", (int)(id + 1)); } Watermark *WatermarkManager::GetWatermarkByValue(const std::string &value) const { for (size_t i = 0; i < count(); i++) { Watermark *watermark = item(i); if (watermark->value() == value) return watermark; } return NULL; } bool WatermarkManager::IsUniqueWatermark(const std::string &value) const { for (size_t i = 0; i < count(); i++) { Watermark *watermark = item(i); if (Watermark::AreSimilar(watermark->value(), value)) return false; } return true; } std::string WatermarkManager::CreateValue() const { std::string res; res.reserve(2 * (20 + 0xFF)); do { res.clear(); size_t c = 20 + rand() % 0x100; for (size_t i = 0; i < 2 * c; i++) { if (rand() & 1) res += '?'; else res += string_format("%x", rand() % 0x10); } } while (!IsUniqueWatermark(res)); return res; } /** * Core */ Core::Core(ILog *log /*=NULL*/) : IObject(), log_(log), input_file_(NULL), output_file_(NULL), watermark_(NULL), output_architecture_(NULL), options_(0), vm_options_(0) { #ifdef ULTIMATE licensing_manager_ = new LicensingManager(this); file_manager_ = new FileManager(this); #endif watermark_manager_ = new WatermarkManager(this); template_manager_ = new ProjectTemplateManager(this); script_ = new Script(this); #ifdef __APPLE__ watermark_manager_->ReadFromFile(settings_file()); #else if (settings_file().watermarks_node_created()) { // convert old settings file into new format std::string ini_file_name = os::CombinePaths(os::GetSysAppDataDirectory().c_str(), "PolyTech/VMProtect/VMProtect.ini"); if (os::FileExists(ini_file_name.c_str())) { watermark_manager_->ReadFromIni(ini_file_name); watermark_manager_->SaveToFile(settings_file()); settings_file().Save(); } } else { watermark_manager_->ReadFromFile(settings_file()); } #endif template_manager_->ReadFromFile(settings_file()); } Core::~Core() { Close(); delete script_; delete watermark_manager_; delete template_manager_; #ifdef ULTIMATE delete file_manager_; delete licensing_manager_; #endif } static std::string GetProjectFileName(std::string &exe_file_name) { TiXmlDocument doc; std::string project_file_name = exe_file_name; if (doc.LoadFile(project_file_name.c_str())) { TiXmlElement *root_node = doc.FirstChildElement("Document"); if (root_node) { exe_file_name.clear(); TiXmlElement *protection_node = root_node->FirstChildElement("Protection"); if (protection_node) protection_node->QueryStringAttribute("InputFileName", &exe_file_name); if (!exe_file_name.empty()) exe_file_name = os::CombinePaths(os::ExtractFilePath(project_file_name.c_str()).c_str(), exe_file_name.c_str()); return project_file_name; } } IniFile ini_file(exe_file_name.c_str()); if (ini_file.ReadSection("ProjectInfo").size()) { exe_file_name = ini_file.ReadString("ProjectInfo", "InputFileName"); if (!exe_file_name.empty()) exe_file_name = os::CombinePaths(os::ExtractFilePath(project_file_name.c_str()).c_str(), exe_file_name.c_str()); return project_file_name; } std::string file_name_new = exe_file_name + ".vmp"; std::string file_name_old = os::ChangeFileExt(exe_file_name.c_str(), ".vmp"); if (os::FileExists(file_name_new.c_str()) || !os::FileExists(file_name_old.c_str())) return file_name_new; return file_name_old; } std::string Core::default_output_file_name() const { std::string res = input_file_name_; std::string ext = os::ExtractFileExt(res.c_str()); if (ext.empty()) return res + "_vmp"; return os::ChangeFileExt(res.c_str(), ".vmp") + ext; } #ifdef ULTIMATE std::string Core::default_license_data_file_name() const { return os::ExtractFileName(project_file_name_.c_str()); } #endif #ifdef ULTIMATE bool Core::Open(const std::string &file_name, const std::string &user_project_file_name, const std::string &user_licensing_params_file_name) #else bool Core::Open(const std::string &file_name, const std::string &user_project_file_name) #endif { std::string exe_file_name; size_t i; Close(); exe_file_name = file_name; project_file_name_ = (user_project_file_name.empty()) ? GetProjectFileName(exe_file_name) : user_project_file_name; #ifdef __APPLE__ std::string new_file_name = os::GetMainExeFileName(exe_file_name.c_str()); if (!new_file_name.empty()) exe_file_name = new_file_name; #endif if (!exe_file_name.empty()) { if (log_) log_->StartProgress(string_format("%s %s...", language[lsLoading].c_str(), os::ExtractFileName(exe_file_name.c_str()).c_str()), 1); std::auto_ptr file[] = { std::auto_ptr(new PEFile(log_)), std::auto_ptr(new MacFile(log_)), std::auto_ptr(new ELFFile(log_)) }; std::string open_error; for (i = 0; i < _countof(file); i++) { open_error.clear(); OpenStatus status = file[i]->Open(exe_file_name.c_str(), foRead | foCopyToTemp, &open_error); if (status == osSuccess) { IArchitecture *arch = file[i]->item(0); ISection *code_segment = NULL; for (size_t j = 0; j < arch->segment_list()->count(); j++) { ISection *segment = arch->segment_list()->item(j); if (segment->physical_size() && (segment->memory_type() & mtExecutable)) { code_segment = segment; break; } } if (!code_segment) { Notify(mtError, NULL, string_format(language[lsFileHasNoCodeSegment].c_str(), exe_file_name.c_str())); return false; } delete input_file_; input_file_ = file[i].release(); break; } else { switch (status) { case osOpenError: Notify(mtError, NULL, string_format(language[lsOpenFileError].c_str(), exe_file_name.c_str(), file[i]->format_name().c_str())); break; case osInvalidFormat: Notify(mtError, NULL, string_format(language[lsFileHasIncorrectFormat].c_str(), exe_file_name.c_str(), file[i]->format_name().c_str()) + (!open_error.empty() ? ": " + open_error : "")); break; case osUnsupportedCPU: Notify(mtError, NULL, string_format(language[lsFileHasUnsupportedProcessor].c_str(), exe_file_name.c_str(), file[i]->item(0)->name().c_str())); break; case osUnsupportedSubsystem: Notify(mtError, NULL, string_format(language[lsFileHasUnsupportedSubsystem].c_str(), exe_file_name.c_str())); break; } if (status != osUnknownFormat) return false; } } if (!input_file_) { Notify(mtError, NULL, string_format(language[lsFileHasUnknownFormat].c_str(), exe_file_name.c_str())); return false; } if (input_file_->visible_count() == 0) return false; } #ifndef ULTIMATE if (!input_file_) return false; #endif // set default values ProjectTemplate *default_template = template_manager_->item(0); options_ = default_template->options(); vm_options_ = 0; vm_section_name_ = default_template->vm_section_name(); for (i = 0; i < _countof(messages_); i++) { messages_[i] = default_template->message(i); } if (!LoadFromXML(project_file_name_.c_str()) && !LoadFromIni(project_file_name_.c_str())) { if (input_file_) { if (log_) log_->StartProgress(string_format("%s %s...", language[lsLoading].c_str(), os::ExtractFileName(project_file_name_.c_str()).c_str()), 0); LoadDefaultFunctions(); if (log_) log_->EndProgress(); } } if (input_file_name_.empty()) input_file_name_ = os::SubtractPath(project_path().c_str(), exe_file_name.c_str()); if (output_file_name_.empty()) output_file_name_ = default_output_file_name(); #ifdef ULTIMATE if (!user_licensing_params_file_name.empty()) license_data_file_name_ = user_licensing_params_file_name; if (license_data_file_name_.empty()) license_data_file_name_ = default_license_data_file_name(); licensing_manager_->Open(os::CombinePaths(project_path().c_str(), license_data_file_name_.c_str())); #endif return true; } bool Core::LoadFromXML(const char *project_file_name) { TiXmlDocument doc; TiXmlElement *root_node, *script_node, *protection_node, *procedures_node, *procedure_node, *objects_node, *object_node, *messages_node, *message_node, *folders_node, *folder_node, *ext_command_node; size_t i, j; CompilationType compilation_type; uint64_t func_address, address; bool need_compile; std::string func_name, arch_name; IFunction *function; IArchitecture *arch; uint32_t compilation_options; unsigned int u, version; unsigned int func_index; if (!doc.LoadFile(project_file_name)) return false; root_node = doc.FirstChildElement("Document"); if (!root_node) return false; version = 1; root_node->QueryUnsignedAttribute("Version", &version); if (input_file_) { protection_node = root_node ? root_node->FirstChildElement("Protection") : NULL; if (log_) { i = 0; if (protection_node) { procedures_node = protection_node->FirstChildElement("Procedures"); if (procedures_node) { procedure_node = procedures_node->FirstChildElement("Procedure"); while (procedure_node) { i++; procedure_node = procedure_node->NextSiblingElement("Procedure"); } } } log_->StartProgress(string_format("%s %s...", language[lsLoading].c_str(), os::ExtractFileName(project_file_name).c_str()), i); } if (protection_node) { protection_node->QueryStringAttribute("InputFileName", &input_file_name_); u = options_; protection_node->QueryUnsignedAttribute("Options", &u); options_ = u; u = 0; protection_node->QueryUnsignedAttribute("VMOptions", &u); vm_options_ = u; if (version < 2) { bool check_kernel_debugger = false; protection_node->QueryBoolAttribute("CheckKernelDebugger", &check_kernel_debugger); if (check_kernel_debugger) options_ |= cpCheckKernelDebugger; } protection_node->QueryStringAttribute("VMCodeSectionName", &vm_section_name_); protection_node->QueryStringAttribute("OutputFileName", &output_file_name_); protection_node->QueryStringAttribute("WaterMarkName", &watermark_name_); #ifdef ULTIMATE protection_node->QueryStringAttribute("HWID", &hwid_); protection_node->QueryStringAttribute("LicenseDataFileName", &license_data_file_name_); #endif messages_node = protection_node->FirstChildElement("Messages"); if (messages_node) { message_node = messages_node->FirstChildElement("Message"); while (message_node) { u = 0; message_node->QueryUnsignedAttribute("Id", &u); if (u < _countof(messages_)) { if (const char *text = message_node->GetText()) messages_[u] = text; else messages_[u].clear(); } message_node = message_node->NextSiblingElement(message_node->Value()); } } if (version < 2) { options_ |= cpStripDebugInfo; } std::vector folder_list; Folder *parent_folder; folders_node = protection_node->FirstChildElement("Folders"); if (folders_node) { folder_node = folders_node->FirstChildElement("Folder"); while (folder_node) { u = -1; std::string name; folder_node->QueryUnsignedAttribute("Parent", &u); folder_node->QueryStringAttribute("Name", &name); parent_folder = (u < folder_list.size()) ? folder_list[u] : input_file_->folder_list(); folder_list.push_back(parent_folder->Add(name)); folder_node = folder_node->NextSiblingElement(folder_node->Value()); } } procedures_node = protection_node->FirstChildElement("Procedures"); if (procedures_node) { std::vector address_list; procedure_node = procedures_node->FirstChildElement("Procedure"); while (procedure_node) { arch_name.clear(); procedure_node->QueryStringAttribute("Architecture", &arch_name); u = ctVirtualization; procedure_node->QueryUnsignedAttribute("CompilationType", &u); if (u > 2) u = 0; compilation_type = static_cast(u); u = 0; procedure_node->QueryUnsignedAttribute("Options", &u); compilation_options = u; need_compile = true; procedure_node->QueryBoolAttribute("IncludedInCompilation", &need_compile); u = -1; procedure_node->QueryUnsignedAttribute("Folder", &u); parent_folder = (u < folder_list.size()) ? folder_list[u] : NULL; func_name.clear(); procedure_node->QueryStringAttribute("MapAddress", &func_name); func_address = 0; func_index = (unsigned int)-1; if (func_name.empty()) { std::string str; procedure_node->QueryStringAttribute("Address", &str); func_address = StrToInt64Def(str.c_str(), 0); } else { procedure_node->QueryUnsignedAttribute("Index", &func_index); } for (i = 0; i < input_file_->count(); i++) { arch = input_file_->item(i); if (!arch->visible()) continue; struct AddressInfo { IArchitecture *arch; uint64_t address; }; std::vector address_info_list; AddressInfo address_info; address_info.arch = arch; if (func_name.empty()) { address_info.address = func_address; address_info_list.push_back(address_info); } else { address_list = arch->map_function_list()->GetAddressListByName(func_name, true); for (j = 0; j < address_list.size(); j++) { address_info.address = address_list[j]; address_info_list.push_back(address_info); } } if (!func_name.empty()) { if (func_index != (unsigned int)-1) { if (func_index < address_info_list.size()) { address_info = address_info_list[func_index]; address_info_list.clear(); address_info_list.push_back(address_info); } else { address_info_list.clear(); } } if (address_list.empty()) { function = arch->function_list()->AddUnknown(func_name, compilation_type, compilation_options, need_compile, parent_folder); function->set_tag(func_index); } } for (j = 0; j < address_info_list.size(); j++) { address_info = address_info_list[j]; address = address_info.address; arch = address_info.arch; function = arch->function_list()->AddByAddress(address_info.address, compilation_type, compilation_options, need_compile, parent_folder); if (function) { u = 0; procedure_node->QueryUnsignedAttribute("BreakOffset", &u); if (u) function->set_break_address(address + u); ext_command_node = procedure_node->FirstChildElement("ExtOffset"); while (ext_command_node) { if (const char *str = ext_command_node->GetText()) function->ext_command_list()->Add(address + strtoul(str, 0, 10)); ext_command_node = ext_command_node->NextSiblingElement("ExtOffset"); } } } } procedure_node = procedure_node->NextSiblingElement(procedure_node->Value()); if (log_) log_->StepProgress(1ull, true); } } objects_node = protection_node->FirstChildElement("Objects"); if (objects_node) { std::string name; std::string type; object_node = objects_node->FirstChildElement("Object"); while (object_node) { arch_name.clear(); object_node->QueryStringAttribute("Architecture", &arch_name); type.clear(); object_node->QueryStringAttribute("Type", &type); name.clear(); object_node->QueryStringAttribute("Name", &name); for (i = 0; i < input_file_->count(); i++) { arch = input_file_->item(i); if (!arch->visible()) continue; if (!arch_name.empty() && arch->name() != arch_name) continue; if (type == "Segment") { if (ISection *segment = arch->segment_list()->GetSectionByName(name)) { bool excluded_from_packing = false; object_node->QueryBoolAttribute("ExcludedFromPacking", &excluded_from_packing); bool excluded_from_memory_protection = false; object_node->QueryBoolAttribute("ExcludedFromMemoryProtection", &excluded_from_memory_protection); segment->set_excluded_from_packing(excluded_from_packing); segment->set_excluded_from_memory_protection(excluded_from_memory_protection); } } else if (type == "Resource" && arch->resource_list()) { if (IResource *resource = arch->resource_list()->GetResourceById(name)) { bool excluded_from_packing = false; object_node->QueryBoolAttribute("ExcludedFromPacking", &excluded_from_packing); resource->set_excluded_from_packing(excluded_from_packing); } } else if (type == "Import") { if (IImport *import = arch->import_list()->GetImportByName(name)) { bool excluded_from_import_protection = false; object_node->QueryBoolAttribute("ExcludedFromImportProtection", &excluded_from_import_protection); import->set_excluded_from_import_protection(excluded_from_import_protection); } } } object_node = object_node->NextSiblingElement(object_node->Value()); } } } LoadDefaultFunctions(); if (log_) log_->EndProgress(); } #ifdef ULTIMATE TiXmlElement *files_node = root_node ? root_node->FirstChildElement("DLLBox") : NULL; if (files_node) { std::vector folder_list; FileFolder *parent_folder; folders_node = files_node->FirstChildElement("Folders"); if (folders_node) { folder_node = folders_node->FirstChildElement("Folder"); while (folder_node) { u = -1; std::string name; folder_node->QueryUnsignedAttribute("Parent", &u); folder_node->QueryStringAttribute("Name", &name); parent_folder = (u < folder_list.size()) ? folder_list[u] : file_manager_->folder_list(); folder_list.push_back(parent_folder->Add(name)); folder_node = folder_node->NextSiblingElement(folder_node->Value()); } } need_compile = true; files_node->QueryBoolAttribute("IncludedInCompilation", &need_compile); file_manager_->set_need_compile(need_compile); TiXmlElement *file_node = files_node->FirstChildElement("DLL"); while (file_node) { std::string name; std::string file_name; file_node->QueryStringAttribute("Name", &name); file_node->QueryStringAttribute("FileName", &file_name); u = -1; file_node->QueryUnsignedAttribute("Folder", &u); parent_folder = (u < folder_list.size()) ? folder_list[u] : NULL; InternalFileAction action = faNone; if (version < 2) { bool load_at_start = false; file_node->QueryBoolAttribute("LoadAtStart", &load_at_start); if (load_at_start) action = faLoad; } else { u = 0; file_node->QueryUnsignedAttribute("Options", &u); if (u & 1) action = faLoad; else if (u & 2) action = faRegister; else if (u & 4) action = faInstall; } file_manager_->Add(name, file_name, action, parent_folder); file_node = file_node->NextSiblingElement(file_node->Value()); } } #endif script_node = root_node ? root_node->FirstChildElement("Script") : NULL; if (script_node) { need_compile = true; script_node->QueryBoolAttribute("IncludedInCompilation", &need_compile); script_->set_need_compile(need_compile); const char *str = script_node->GetText(); if (str) script_->set_text(std::string(str)); } return true; } bool Core::LoadFromIni(const char *project_file_name) { size_t i, c, j, k, u, version; std::vector folder_list; Folder *parent_folder; bool need_compile; uint64_t address; CompilationType compilation_type; uint32_t compilation_options; std::string map_address; IFunction *function; IArchitecture *arch; IniFile doc(project_file_name); if (doc.ReadSection("ProjectInfo").empty()) return false; if (input_file_) { if (log_) { i = doc.ReadInt("ProjectInfo", "Count"); log_->StartProgress(string_format("%s %s...", language[lsLoading].c_str(), os::ExtractFileName(project_file_name).c_str()), i); } version = doc.ReadInt("ProjectInfo", "Version", 1); input_file_name_ = doc.ReadString("ProjectInfo", "InputFileName"); options_ = doc.ReadInt("ProjectInfo", "Options", options_); bool check_kernel_debugger = doc.ReadBool("ProjectInfo", "CheckKernelModeDebugger", false); if (check_kernel_debugger) options_ |= cpCheckKernelDebugger; vm_section_name_ = doc.ReadString("ProjectInfo", "VMCodeSectionName", vm_section_name_.c_str()); output_file_name_ = doc.ReadString("ProjectInfo", "OutputFileName"); watermark_name_ = doc.ReadString("ProjectInfo", "WaterMarkName"); if (version < 2) { options_ |= cpStripDebugInfo; } c = doc.ReadInt("Folders", "Count"); for (i = 0; i < c; i++) { u = doc.ReadInt("Folders", string_format("ParentFolder%d", i).c_str(), -1); parent_folder = (u < folder_list.size()) ? folder_list[u] : input_file_->folder_list(); folder_list.push_back(parent_folder->Add(doc.ReadString("Folders", string_format("FolderName%d", i).c_str()))); } c = doc.ReadInt("ProjectInfo", "Count"); std::vectoraddress_list; for (i = 0; i < c; i++) { u = doc.ReadInt("Procedures", string_format("CompilationType%d", i).c_str(), ctVirtualization); if (u > 2) u = 0; compilation_type = static_cast(u); compilation_options = doc.ReadInt("Procedures", string_format("Options%d", i).c_str()); need_compile = doc.ReadBool("Procedures", string_format("NeedCompile%d", i).c_str()); u = doc.ReadInt("Procedures", string_format("ParentFolder%d", i).c_str(), -1); parent_folder = (u < folder_list.size()) ? folder_list[u] : NULL; map_address = doc.ReadString("Procedures", string_format("MapAddress%d", i).c_str()); for (j = 0; j < input_file_->count(); j++) { arch = input_file_->item(j); if (!arch->visible()) continue; if (map_address.empty()) { address_list.clear(); address_list.push_back(doc.ReadInt64("Procedures", string_format("Address%d", i).c_str())); } else { address_list = arch->map_function_list()->GetAddressListByName(map_address, true); if (address_list.empty()) { function = arch->function_list()->AddUnknown(map_address, compilation_type, compilation_options, need_compile, parent_folder); function->set_tag(-1); } } for (k = 0; k < address_list.size(); k++) { address = address_list[k]; function = arch->function_list()->AddByAddress(address, compilation_type, compilation_options, need_compile, parent_folder); if (function) { u = doc.ReadInt("Procedures", string_format("BreakAddress%d", i).c_str()); if (u) function->set_break_address(address + u); size_t e = doc.ReadInt("Procedures", string_format("ExtAddressCount%d", i).c_str()); for (size_t k = 0; k < e; k++) { u = doc.ReadInt(string_format("ExtAddress%d", i).c_str(), string_format("Address%d", k).c_str()); function->ext_command_list()->Add(address + u); } } } } if (log_) log_->StepProgress(1ull, true); } LoadDefaultFunctions(); if (log_) log_->EndProgress(); } #ifdef ULTIMATE c = doc.ReadInt("DLLs", "Count"); for (i = 0; i < c; i++) { file_manager_->Add(doc.ReadString("DLLs", string_format("DLLName%d", i).c_str()), doc.ReadString("DLLs", string_format("DLLFileName%d", i).c_str()), faNone, NULL); } #endif std::string script_file_name = os::ChangeFileExt(doc.file_name().c_str(), ".vms"); if (os::FileExists(script_file_name.c_str())) script_->LoadFromFile(script_file_name); return true; } void Core::LoadDefaultFunctions() { if (!input_file_) return; // add new markers and strings into project Folder *parent_folder = NULL; for (size_t i = 0; i < input_file_->count(); i++) { IArchitecture *arch = input_file_->item(i); if (!arch->visible()) continue; for (size_t j = 0; j < arch->map_function_list()->count(); j++) { IFunctionList *function_list = arch->function_list(); MapFunction *map_function = arch->map_function_list()->item(j); if ((map_function->type() == otMarker || map_function->type() == otAPIMarker || map_function->type() == otString) && function_list->GetFunctionByAddress(map_function->address()) == NULL) { if (!parent_folder) { parent_folder = input_file_->folder_list()->Add("New markers and strings"); parent_folder->set_read_only(true); } function_list->AddByAddress(map_function->address(), ctVirtualization, 0, true, parent_folder); } } } } void Core::LoadFromTemplate(const ProjectTemplate &pt) { set_options(pt.options()); set_vm_section_name(pt.vm_section_name()); for (size_t i = 0; i < _countof(messages_); i++) { set_message(i, pt.message(i)); } } bool Core::SaveAs(const std::string &file_name) { std::string old_project_file_name = project_file_name_; std::string old_input_file_name = input_file_name_; std::string old_output_file_name = output_file_name_; #ifdef ULTIMATE std::string old_license_data_file_name = license_data_file_name_; #endif std::string new_project_path = os::ExtractFilePath(file_name.c_str()); input_file_name_ = os::SubtractPath(new_project_path.c_str(), os::CombinePaths(project_path().c_str(), input_file_name().c_str()).c_str()); output_file_name_ = os::SubtractPath(new_project_path.c_str(), os::CombinePaths(project_path().c_str(), output_file_name().c_str()).c_str()); #ifdef ULTIMATE license_data_file_name_ = os::SubtractPath(new_project_path.c_str(), os::CombinePaths(project_path().c_str(), license_data_file_name().c_str()).c_str()); #endif project_file_name_ = file_name; if (!Save()) { input_file_name_ = old_input_file_name; output_file_name_ = old_output_file_name; project_file_name_ = old_project_file_name; #ifdef ULTIMATE license_data_file_name_ = old_license_data_file_name; #endif return false; } if (output_file_name_ != old_output_file_name #ifdef ULTIMATE || license_data_file_name_ != old_license_data_file_name #endif ) Notify(mtChanged, this); return true; } bool Core::Save() { if (input_file_) { size_t i, j, k; TiXmlDocument doc; unsigned int old_version; if (!doc.LoadFile(project_file_name_.c_str())) doc.LinkEndChild(new TiXmlDeclaration("1.0", "UTF-8", "")); TiXmlElement *root_node = doc.FirstChildElement("Document"); if (!root_node) { root_node = new TiXmlElement("Document"); doc.LinkEndChild(root_node); } old_version = 1; root_node->QueryUnsignedAttribute("Version", &old_version); root_node->SetAttribute("Version", 2); TiXmlElement *protection_node = root_node->FirstChildElement("Protection"); if (!protection_node) { protection_node = new TiXmlElement("Protection"); root_node->LinkEndChild(protection_node); } protection_node->SetAttribute("InputFileName", input_file_name_); protection_node->SetAttribute("Options", options_); protection_node->SetAttribute("VMCodeSectionName", vm_section_name_); #ifdef ULTIMATE if (!hwid_.empty()) protection_node->SetAttribute("HWID", hwid_); else protection_node->RemoveAttribute("HWID"); if (license_data_file_name_ != default_license_data_file_name()) { protection_node->SetAttribute("LicenseDataFileName", license_data_file_name_); } else { protection_node->RemoveAttribute("LicenseDataFileName"); } #endif if (output_file_name_ != default_output_file_name()) { protection_node->SetAttribute("OutputFileName", output_file_name_); } else { protection_node->RemoveAttribute("OutputFileName"); } if (!watermark_name_.empty()) { protection_node->SetAttribute("WaterMarkName", watermark_name_); } else { protection_node->RemoveAttribute("WaterMarkName"); } TiXmlElement *messages_node = protection_node->FirstChildElement("Messages"); if (!messages_node) { messages_node = new TiXmlElement("Messages"); protection_node->LinkEndChild(messages_node); } else { messages_node->Clear(); } for (i = 0; i < _countof(messages_); i++) { std::string message = messages_[i]; if (message != #ifdef VMP_GNU default_message[i] #else os::ToUTF8(default_message[i]) #endif ) { TiXmlElement *message_node = new TiXmlElement("Message"); messages_node->LinkEndChild(message_node); message_node->SetAttribute("Id", (int)i); message_node->LinkEndChild(new TiXmlText(message)); } } TiXmlElement *folders_node = protection_node->FirstChildElement("Folders"); if (!folders_node) { folders_node = new TiXmlElement("Folders"); protection_node->LinkEndChild(folders_node); } else { folders_node->Clear(); } std::vector folder_list = input_file_->folder_list()->GetFolderList(true); for (i = 0; i < folder_list.size(); i++) { Folder *folder = folder_list[i]; TiXmlElement *folder_node = new TiXmlElement("Folder"); folders_node->LinkEndChild(folder_node); folder_node->SetAttribute("Name", folder->name()); std::vector::const_iterator it = std::find(folder_list.begin(), folder_list.end(), folder->owner()); if (it != folder_list.end()) folder_node->SetAttribute("Parent", (int)(it - folder_list.begin())); } TiXmlElement *procedures_node = protection_node->FirstChildElement("Procedures"); if (!procedures_node) { procedures_node = new TiXmlElement("Procedures"); protection_node->LinkEndChild(procedures_node); } else { procedures_node->Clear(); } std::map > > function_map; std::map function_index; size_t arch_count = input_file_->visible_count(); bool show_arch_name = input_file_->function_list()->show_arch_name(); for (k = 0; k < input_file_->count(); k++) { IArchitecture *arch = input_file_->item(k); if (!arch->visible()) continue; for (i = 0; i < arch->function_list()->count(); i++) { IFunction *function = arch->function_list()->item(i); if (function->name().empty()) continue; Data hash = function->hash(); std::map > >::iterator it = function_map.find(hash); if (it == function_map.end()) { function_map[hash][arch].push_back(function); } else { it->second[arch].push_back(function); } } } for (std::map > >::iterator it = function_map.begin(); it != function_map.end(); it++) { for (std::map >::iterator arch_it = it->second.begin(); arch_it != it->second.end(); arch_it++) { IArchitecture *arch = arch_it->first; std::vector address_list; for (i = 0; i < arch_it->second.size(); i++) { IFunction *function = arch_it->second[i]; if (i == 0) address_list = arch->map_function_list()->GetAddressListByName(function->name(), true); if (function->type() == otUnknown) { function_index[function] = (function->tag() == 0xff) ? -1 : function->tag(); } else { if (address_list.size() == arch_it->second.size()) { function_index[function] = -1; } else { std::vector::iterator address_it = std::find(address_list.begin(), address_list.end(), function->address()); if (address_it != address_list.end()) function_index[function] = address_it - address_list.begin(); } } } } } std::string arch_name; size_t first_arch_index = -1; for (k = 0; k < input_file_->count(); k++) { IArchitecture *arch = input_file_->item(k); if (!arch->visible()) continue; if (first_arch_index == NOT_ID) first_arch_index = k; for (i = 0; i < arch->function_list()->count(); i++) { IFunction *function = arch->function_list()->item(i); size_t map_index = -1; arch_name = arch->name(); if (!function->name().empty()) { std::map::iterator index_it = function_index.find(function); if (index_it == function_index.end()) continue; map_index = index_it->second; std::map > >::iterator it = function_map.find(function->hash()); if (it != function_map.end()) { if (it->second.empty() || it->second[arch].empty()) continue; if (show_arch_name) { if (it->second.size() == arch_count && k == first_arch_index) { bool is_equal = true; std::vector source_index_list; for (std::map >::iterator arch_it = it->second.begin(); arch_it != it->second.end(); arch_it++) { std::vector index_list; for (j = 0; j < it->second[arch].size(); j++) { index_it = function_index.find(function); if (index_it != function_index.end()) { index_list.push_back(index_it->second); if (index_it->second == NOT_ID) break; } } if (source_index_list.empty()) source_index_list = index_list; else { if (source_index_list.size() == index_list.size()) { for (j = 0; j < source_index_list.size(); j++) { if (std::find(index_list.begin(), index_list.end(), source_index_list[j]) == index_list.end()) { is_equal = false; break; } } } else is_equal = false; if (!is_equal) break; } } if (is_equal) { it->second.clear(); arch_name.clear(); } } } if (map_index == NOT_ID && !it->second.empty()) it->second[arch].clear(); } } TiXmlElement *procedure_node = new TiXmlElement("Procedure"); procedures_node->LinkEndChild(procedure_node); if (show_arch_name && !arch_name.empty()) procedure_node->SetAttribute("Architecture", arch_name); if (function->name().empty()) { procedure_node->SetAttribute("Address", string_format("%llu", function->address())); } else { procedure_node->SetAttribute("MapAddress", function->name()); if (map_index != NOT_ID) procedure_node->SetAttribute("Index", (int)map_index); } if (!function->need_compile()) procedure_node->SetAttribute("IncludedInCompilation", function->need_compile()); procedure_node->SetAttribute("Options", function->compilation_options()); std::vector::const_iterator it = std::find(folder_list.begin(), folder_list.end(), function->folder()); if (it != folder_list.end()) procedure_node->SetAttribute("Folder", (int)(it - folder_list.begin())); if (function->compilation_type() != ctVirtualization) procedure_node->SetAttribute("CompilationType", function->compilation_type()); if (function->break_address()) procedure_node->SetAttribute("BreakOffset", static_cast(function->break_address() - function->address())); for (j = 0; j < function->ext_command_list()->count(); j++) { TiXmlElement *ext_command_node = new TiXmlElement("ExtOffset"); procedure_node->LinkEndChild(ext_command_node); ext_command_node->LinkEndChild(new TiXmlText(string_format("%d", static_cast(function->ext_command_list()->item(j)->address() - function->address())))); } } } TiXmlElement *objects_node = protection_node->FirstChildElement("Objects"); if (!objects_node) { objects_node = new TiXmlElement("Objects"); protection_node->LinkEndChild(objects_node); } else { objects_node->Clear(); } std::map segment_map; std::map resource_map; std::map import_map; if (show_arch_name) { for (k = 0; k < input_file_->count(); k++) { IArchitecture *arch = input_file_->item(k); if (!arch->visible()) continue; for (i = 0; i < arch->segment_list()->count(); i++) { ISection *segment = arch->segment_list()->item(i); if (!segment->excluded_from_packing() && !segment->excluded_from_memory_protection()) continue; Data hash = segment->hash(); std::map::iterator it = segment_map.find(hash); if (it == segment_map.end()) segment_map[hash] = 1; else it->second++; } if (arch->resource_list()) { std::vector resource_list = arch->resource_list()->GetResourceList(); for (i = 0; i < resource_list.size(); i++) { IResource *resource = resource_list[i]; if (!resource->excluded_from_packing()) continue; Data hash = resource->hash(); std::map::iterator it = resource_map.find(hash); if (it == resource_map.end()) resource_map[hash] = 1; else it->second++; } } for (i = 0; i < arch->import_list()->count(); i++) { IImport *import = arch->import_list()->item(i); if (!import->excluded_from_import_protection()) continue; Data hash = import->hash(); std::map::iterator it = import_map.find(hash); if (it == import_map.end()) import_map[hash] = 1; else it->second++; } } } for (k = 0; k < input_file_->count(); k++) { IArchitecture *arch = input_file_->item(k); if (!arch->visible()) continue; for (i = 0; i < arch->segment_list()->count(); i++) { ISection *segment = arch->segment_list()->item(i); if (!segment->excluded_from_packing() && !segment->excluded_from_memory_protection()) continue; if (show_arch_name) { arch_name = arch->name(); std::map::iterator it = segment_map.find(segment->hash()); if (it != segment_map.end()) { if (it->second == 0) continue; if (it->second == arch_count) { it->second = 0; arch_name.clear(); } } } TiXmlElement *object_node = new TiXmlElement("Object"); objects_node->LinkEndChild(object_node); if (show_arch_name && !arch_name.empty()) object_node->SetAttribute("Architecture", arch_name); object_node->SetAttribute("Type", "Segment"); object_node->SetAttribute("Name", segment->name()); if (segment->excluded_from_packing()) object_node->SetAttribute("ExcludedFromPacking", segment->excluded_from_packing()); if (segment->excluded_from_memory_protection()) object_node->SetAttribute("ExcludedFromMemoryProtection", segment->excluded_from_memory_protection()); } if (arch->resource_list()) { std::vector resource_list = arch->resource_list()->GetResourceList(); for (i = 0; i < resource_list.size(); i++) { IResource *resource = resource_list[i]; if (!resource->excluded_from_packing()) continue; if (show_arch_name) { arch_name = arch->name(); std::map::iterator it = resource_map.find(resource->hash()); if (it != resource_map.end()) { if (it->second == 0) continue; if (it->second == arch_count) { it->second = 0; arch_name.clear(); } } } TiXmlElement *object_node = new TiXmlElement("Object"); objects_node->LinkEndChild(object_node); if (show_arch_name && !arch_name.empty()) object_node->SetAttribute("Architecture", arch_name); object_node->SetAttribute("Type", "Resource"); object_node->SetAttribute("Name", resource->id()); object_node->SetAttribute("ExcludedFromPacking", resource->excluded_from_packing()); } } for (i = 0; i < arch->import_list()->count(); i++) { IImport *import = arch->import_list()->item(i); if (!import->excluded_from_import_protection()) continue; if (show_arch_name) { arch_name = arch->name(); std::map::iterator it = import_map.find(import->hash()); if (it != import_map.end()) { if (it->second == 0) continue; if (it->second == arch_count) { it->second = 0; arch_name.clear(); } } } TiXmlElement *object_node = new TiXmlElement("Object"); objects_node->LinkEndChild(object_node); if (show_arch_name && !arch_name.empty()) object_node->SetAttribute("Architecture", arch_name); object_node->SetAttribute("Type", "Import"); object_node->SetAttribute("Name", import->name()); if (import->excluded_from_import_protection()) object_node->SetAttribute("ExcludedFromImportProtection", import->excluded_from_import_protection()); } } #ifdef ULTIMATE { TiXmlElement *files_node = root_node->FirstChildElement("DLLBox"); if (!files_node) { files_node = new TiXmlElement("DLLBox"); root_node->LinkEndChild(files_node); } else { files_node->Clear(); } folders_node = new TiXmlElement("Folders"); files_node->LinkEndChild(folders_node); std::vector folder_list = file_manager_->folder_list()->GetFolderList(); for (i = 0; i < folder_list.size(); i++) { FileFolder *folder = folder_list[i]; TiXmlElement *folder_node = new TiXmlElement("Folder"); folders_node->LinkEndChild(folder_node); folder_node->SetAttribute("Name", folder->name()); std::vector::const_iterator it = std::find(folder_list.begin(), folder_list.end(), folder->owner()); if (it != folder_list.end()) folder_node->SetAttribute("Parent", (int)(it - folder_list.begin())); } if (!file_manager_->need_compile()) files_node->SetAttribute("IncludedInCompilation", file_manager_->need_compile()); else files_node->RemoveAttribute("IncludedInCompilation"); for (i = 0; i < file_manager_->count(); i++) { InternalFile *file = file_manager_->item(i); TiXmlElement *file_node = new TiXmlElement("DLL"); files_node->LinkEndChild(file_node); file_node->SetAttribute("Name", file->name()); file_node->SetAttribute("FileName", file->file_name()); int options; switch (file->action()) { case faLoad: options = 1; break; case faRegister: options = 2; break; case faInstall: options = 4; break; default: options = 0; break; } if (options) file_node->SetAttribute("Options", options); std::vector::const_iterator it = std::find(folder_list.begin(), folder_list.end(), file->folder()); if (it != folder_list.end()) file_node->SetAttribute("Folder", (int)(it - folder_list.begin())); } } #endif TiXmlElement *script_node = root_node->FirstChildElement("Script"); if (!script_node) { script_node = new TiXmlElement("Script"); root_node->LinkEndChild(script_node); } else { script_node->Clear(); } if (!script_->need_compile()) script_node->SetAttribute("IncludedInCompilation", script_->need_compile()); else script_node->RemoveAttribute("IncludedInCompilation"); if (!script_->text().empty()) { std::string st = script_->text(); st.erase(std::remove(st.begin(), st.end(), '\r'), st.end()); TiXmlText *stn = new TiXmlText(st); stn->SetCDATA(true); //readability improved script_node->LinkEndChild(stn); } if (!doc.SaveFile(project_file_name_.c_str())) return false; } #ifdef ULTIMATE licensing_manager_->Save(); #endif return true; } void Core::Close() { input_file_name_.clear(); output_file_name_.clear(); watermark_name_.clear(); script_->clear(); script_->set_need_compile(true); #ifdef ULTIMATE hwid_.clear(); licensing_manager_->clear(); file_manager_->clear(); license_data_file_name_.clear(); #endif if (input_file_) { delete input_file_; input_file_ = NULL; } } std::string Core::absolute_output_file_name() const { return os::CombinePaths(project_path().c_str(), os::ExpandEnvironmentVariables(output_file_name_.c_str()).c_str()); } bool Core::Compile() { uint32_t rand_seed = os::GetTickCount(); #ifdef CHECKED std::cout << "------------------- Core::Compile " << __LINE__ << " -------------------" << std::endl; std::cout << "rand_seed: " << rand_seed << std::endl; std::cout << "---------------------------------------------------------" << std::endl; #endif rand_seed = 0; OutputDebugStringA(string_format("rand_seed:%d\n", rand_seed).c_str()); srand(rand_seed); output_file_ = NULL; output_architecture_ = NULL; if (!script_->Compile()) return false; Watermark *watermark = NULL; if (!watermark_name_.empty()) { watermark = watermark_manager_->GetWatermarkByName(watermark_name_); if (!watermark) { Notify(mtError, watermark_manager_, string_format(language[lsWatermarkNotFound].c_str(), watermark_name_.c_str())); return false; } if (!watermark->enabled()) { Notify(mtError, watermark_manager_, string_format(language[lsWatermarkIsDisabled].c_str(), watermark_name_.c_str())); return false; } } if (!input_file_) return true; CompileOptions options; options.flags = (options_ & cpUserOptionsMask); options.flags &= ~input_file_->disable_options(); if ((options.flags & cpCheckDebugger) == 0) options.flags &= ~cpCheckKernelDebugger; #ifndef DEMO if (VMProtectGetSerialNumberState() == SERIAL_STATE_SUCCESS) { options.flags |= cpEncryptBytecode; if ((options.flags & cpMemoryProtection) == 0) options.flags |= cpLoaderCRC; } else options.flags |= cpUnregisteredVersion; #endif options.section_name = vm_section_name_; options.vm_flags = vm_options_; options.vm_count = #ifdef DEMO true #else ((options.flags & cpUnregisteredVersion) != 0 || (options.vm_flags & 2) != 0) #endif ? 1 : 10; for (size_t i = 0; i < _countof(options.messages); i++) { options.messages[i] = messages_[i]; } #ifdef DEMO if (true) #else if (options.flags & cpUnregisteredVersion) #endif options.messages[MESSAGE_HWID_MISMATCHED] = #ifdef VMP_GNU VMProtectDecryptStringA(MESSAGE_UNREGISTERED_VERSION_STR); #else os::ToUTF8(VMProtectDecryptStringW(MESSAGE_UNREGISTERED_VERSION_STR)); #endif options.watermark = watermark; options.script = script_; options.architecture = &output_architecture_; #ifdef ULTIMATE options.hwid = hwid_; options.licensing_manager = licensing_manager_; if (file_manager_->need_compile() && file_manager_->count()) options.file_manager = file_manager_; #endif if (log_) log_->StartProgress(string_format("%s...", language[lsCompiling].c_str()), 1); HANDLE locked_file = BeginCompileTransaction(); output_file_->set_log(log_); bool res; try { res = output_file_->Compile(options); } catch(std::runtime_error &) { EndCompileTransaction(locked_file, false); throw; } if (log_) { log_->EndProgress(); log_->set_arch_name(""); } uint32_t output_file_size = static_cast(output_file_->size()); EndCompileTransaction(locked_file, res); if (res) { Notify(mtInformation, NULL, string_format( language[lsOutputFileSize].c_str(), output_file_size, static_cast(100.0 * output_file_size / input_file_->size()) )); if (options.script) options.script->DoAfterCompilation(); } return res; } HANDLE Core::BeginCompileTransaction() { HANDLE res = INVALID_HANDLE_VALUE; std::string output_file_name = absolute_output_file_name(); if (os::FileExists(output_file_name.c_str())) { res = os::FileCreate(output_file_name.c_str(), fmOpenReadWrite | fmShareDenyWrite); if (res == INVALID_HANDLE_VALUE) throw std::runtime_error(string_format(language[lsOpenFileError].c_str(), output_file_name.c_str())); output_file_name = os::GetTempFilePathNameFor(output_file_name.c_str()); if (output_file_name.empty()) throw std::runtime_error(string_format(language[lsCreateFileError].c_str(), "'temporary'")); } output_file_ = input_file_->Clone(output_file_name.c_str()); return res; } void Core::EndCompileTransaction(HANDLE locked_file, bool commit) { std::string output_file = output_file_->file_name(); delete output_file_; output_file_ = NULL; if (locked_file == INVALID_HANDLE_VALUE) { //direct compile to new file, no tmp file created if (!commit) os::FileDelete(output_file.c_str()); //remove new garbage } else { //compiled to tmp file os::FileClose(locked_file); if (commit) { std::string final_file = absolute_output_file_name(); os::FileDelete(final_file.c_str(), true); if (!os::FileMove(output_file.c_str(), final_file.c_str())) { os::FileDelete(output_file.c_str()); throw std::runtime_error(string_format(language[lsCreateFileError].c_str(), final_file.c_str())); } } else { os::FileDelete(output_file.c_str()); } } } void Core::set_options(uint32_t options) { if (options_ != options) { options_ = options; Notify(mtChanged, this); } } void Core::include_option(ProjectOption option) { set_options(options_ | option); } void Core::exclude_option(ProjectOption option) { set_options(options_ & ~option); } void Core::set_vm_section_name(const std::string &vm_section_name) { if (vm_section_name_ != vm_section_name) { vm_section_name_ = vm_section_name; Notify(mtChanged, this); } } void Core::set_watermark_name(const std::string &watermark_name) { if (watermark_name_ != watermark_name) { watermark_name_ = watermark_name; Notify(mtChanged, this); } } void Core::set_output_file_name(const std::string &output_file_name) { if (output_file_name_ != output_file_name) { output_file_name_ = output_file_name.empty() ? default_output_file_name() : output_file_name; Notify(mtChanged, this); } } void Core::set_message(size_t type, const std::string &message) { if (messages_[type] != message) { messages_[type] = message; Notify(mtChanged, this); } } #ifdef ULTIMATE void Core::set_hwid(const std::string &hwid) { if (hwid_ != hwid) { hwid_ = hwid; Notify(mtChanged, this); } } void Core::set_license_data_file_name(const std::string &license_data_file_name) { if (license_data_file_name_ != license_data_file_name) { license_data_file_name_ = license_data_file_name.empty() ? default_license_data_file_name() : license_data_file_name; Notify(mtChanged, this); licensing_manager_->Open(os::CombinePaths(project_path().c_str(), license_data_file_name_.c_str())); } } void Core::set_activation_server(const std::string &activation_server) { if (licensing_manager_->activation_server() != activation_server) { licensing_manager_->set_activation_server(activation_server); Notify(mtChanged, this); } } #endif std::string Core::project_path() const { return os::ExtractFilePath(project_file_name_.c_str()); } void Core::Notify(MessageType type, IObject *sender, const std::string &message) { if (sender) { Watermark *watermark = dynamic_cast(sender); if (watermark) { switch (type) { case mtAdded: case mtChanged: watermark->SaveToFile(settings_file()); break; case mtDeleted: watermark->DeleteFromFile(settings_file()); break; default: // do nothing break; } } ProjectTemplate *pt = dynamic_cast(sender); if (pt) { switch (type) { case mtAdded: case mtChanged: case mtDeleted: template_manager_->SaveToFile(settings_file()); break; default: // do nothing break; } } } if (log_) log_->Notify(type, sender, message); } IArchitecture * Core::input_architecture() const { return (input_file_ && output_architecture_) ? input_file_->GetArchitectureByType(output_architecture_->type()) : NULL; } #include "version.h" const char * Core::version() { return STR(VER_MAJOR) "." STR(VER_MINOR) "." STR(VER_PATCH); } const char * Core::build() { return STR(VER_BUILD); } bool Core::check_license_edition(const VMProtectSerialNumberData &lic) { if (lic.nState != SERIAL_STATE_SUCCESS) return false; uint8_t productId = (lic.nUserDataLength > 0) ? lic.bUserData[0] : VPI_NOT_SPECIFIED; VMProtectProductId allowed[] = { #if defined(ULTIMATE) VPI_NOT_SPECIFIED, VPI_ULTM_PERSONAL, VPI_ULTM_COMPANY #elif defined(LITE) VPI_NOT_SPECIFIED, VPI_ULTM_PERSONAL, VPI_ULTM_COMPANY, VPI_PROF_PERSONAL, VPI_PROF_COMPANY, VPI_LITE_PERSONAL, VPI_LITE_COMPANY #else VPI_NOT_SPECIFIED, VPI_ULTM_PERSONAL, VPI_ULTM_COMPANY, VPI_PROF_PERSONAL, VPI_PROF_COMPANY #endif }; for (size_t i = 0; i < _countof(allowed); i++) { if (productId == allowed[i]) return true; } return false; } #ifdef ULTIMATE /** * License */ License::License(LicensingManager *owner, LicenseDate date, const std::string &customer_name, const std::string &customer_email, const std::string &order_ref, const std::string &comments, const std::string &serial_number, bool blocked) : owner_(owner), date_(date), customer_name_(customer_name), customer_email_(customer_email), order_ref_(order_ref), comments_(comments), serial_number_(serial_number), blocked_(blocked), info_(NULL) { } License::~License() { delete info_; if (owner_) owner_->RemoveObject(this); } void License::GetHash(uint8_t hash[20]) { std::vector binary_serial; Base64ToVector(serial_number_.c_str(), serial_number_.size(), binary_serial); SHA1 sha; sha.Input(&binary_serial[0], binary_serial.size()); const uint8_t *src = sha.Result(); memcpy(hash, src, 20); } void License::set_customer_name(const std::string &value) { if (customer_name_ != value) { customer_name_ = value; Notify(mtChanged, this); } } void License::set_customer_email(const std::string &value) { if (customer_email_ != value) { customer_email_ = value; Notify(mtChanged, this); } } void License::set_order_ref(const std::string &value) { if (order_ref_ != value) { order_ref_ = value; Notify(mtChanged, this); } } void License::set_date(LicenseDate value) { if (date_.value() != value.value()) { date_ = value; Notify(mtChanged, this); } } void License::set_comments(const std::string &value) { if (comments_ != value) { comments_ = value; Notify(mtChanged, this); } } void License::set_blocked(bool value) { if (blocked_ != value) { blocked_ = value; Notify(mtChanged, this); } } void License::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } LicenseInfo *License::info() { if (!info_ && owner_) { LicenseInfo *tmp_info = new LicenseInfo(); if (owner_->DecryptSerialNumber(serial_number_, *tmp_info)) info_ = tmp_info; else delete tmp_info; } return info_; } /** * LicensingManager */ LicensingManager::LicensingManager(Core *owner) : ObjectList(), owner_(owner), algorithm_(alNone), bits_(0), build_date_(0) { } void LicensingManager::clear() { ObjectList::clear(); file_name_.clear(); algorithm_ = alNone; bits_ = 0; product_code_.clear(); public_exp_.clear(); private_exp_.clear(); modulus_.clear(); activation_server_.clear(); } void LicensingManager::changed() { if (owner_) owner_->Notify(mtChanged, this); } bool LicensingManager::Init(size_t key_len) { RSA rsa; if (!rsa.CreateKeyPair(key_len)) return false; std::string file_name = file_name_; clear(); file_name_ = file_name; algorithm_ = alRSA; bits_ = (uint16_t)key_len; public_exp_ = rsa.public_exp(); private_exp_ = rsa.private_exp(); modulus_ = rsa.modulus(); srand(os::GetTickCount()); for (size_t i = 0; i < 8; i++) { product_code_.push_back(rand()); } changed(); return true; } bool LicensingManager::GetLicenseData(Data &data) const { if (algorithm_ == alNone) return false; size_t i; std::vector > black_list; for (i = 0; i < count(); i++) { License *license = item(i); if (!license->blocked()) continue; uint8_t hash[20]; license->GetHash(hash); black_list.push_back(std::vector(hash, hash + sizeof(hash))); } std::sort(black_list.begin(), black_list.end()); uint32_t build_date = build_date_; if (!build_date) { SYSTEM_TIME time; os::GetLocalTime(&time); build_date = (time.year << 16) + (time.month << 8) + time.day; } for (i = 0; i < FIELD_COUNT; i++) { data.PushDWord(0); } data.WriteDWord(FIELD_BUILD_DATE * sizeof(uint32_t), build_date); data.WriteDWord(FIELD_PUBLIC_EXP_OFFSET * sizeof(uint32_t), static_cast(data.size())); data.WriteDWord(FIELD_PUBLIC_EXP_SIZE * sizeof(uint32_t), static_cast(public_exp_.size())); data.PushBuff(public_exp_.data(), public_exp_.size()); data.WriteDWord(FIELD_MODULUS_OFFSET * sizeof(uint32_t), static_cast(data.size())); data.WriteDWord(FIELD_MODULUS_SIZE * sizeof(uint32_t), static_cast(modulus_.size())); data.PushBuff(modulus_.data(), modulus_.size()); data.WriteDWord(FIELD_BLACKLIST_OFFSET * sizeof(uint32_t), static_cast(data.size())); data.WriteDWord(FIELD_BLACKLIST_SIZE * sizeof(uint32_t), static_cast(black_list.size() * 20)); if (!black_list.empty()) { for (i = 0; i < black_list.size(); i++) { data.PushBuff(black_list[i].data(), black_list[i].size()); } } data.WriteDWord(FIELD_ACTIVATION_URL_OFFSET * sizeof(uint32_t), static_cast(data.size())); data.WriteDWord(FIELD_ACTIVATION_URL_SIZE * sizeof(uint32_t), static_cast(activation_server_.size())); if (!activation_server_.empty()) data.PushBuff(activation_server_.data(), activation_server_.size()); data.resize(AlignValue(data.size(), 8)); size_t crc_pos = data.size(); data.WriteDWord(FIELD_CRC_OFFSET * sizeof(uint32_t), static_cast(crc_pos)); // calc CRC SHA1 sha1; sha1.Input(data.data(), crc_pos); data.PushBuff(sha1.Result(), 16); return true; } bool LicensingManager::Open(const std::string &file_name) { clear(); file_name_ = file_name; TiXmlDocument doc; if (!doc.LoadFile(file_name.c_str())) return false; unsigned int u; TiXmlElement *root_node = doc.FirstChildElement("Document"); TiXmlElement *license_manager_node = root_node ? root_node->FirstChildElement("LicenseManager") : NULL; if (license_manager_node) { std::string str; license_manager_node->QueryStringAttribute("Algorithm", &str); if (str.compare("RSA") == 0) { algorithm_ = alRSA; str.clear(); license_manager_node->QueryStringAttribute("ProductCode", &str); Base64ToVector(str.c_str(), str.size(), product_code_); u = 0; license_manager_node->QueryUnsignedAttribute("Bits", &u); bits_ = u; str.clear(); license_manager_node->QueryStringAttribute("PublicExp", &str); Base64ToVector(str.c_str(), str.size(), public_exp_); str.clear(); license_manager_node->QueryStringAttribute("PrivateExp", &str); Base64ToVector(str.c_str(), str.size(), private_exp_); str.clear(); license_manager_node->QueryStringAttribute("Modulus", &str); Base64ToVector(str.c_str(), str.size(), modulus_); license_manager_node->QueryStringAttribute("ActivationServer", &activation_server_); if ((bits_ & 0xf) || bits_ < 1024 || bits_ > 16384 || public_exp_.empty() || private_exp_.empty() || modulus_.empty()) algorithm_ = alNone; } if (algorithm_ != alNone) { TiXmlElement *license_node = license_manager_node->FirstChildElement("License"); while (license_node) { std::string date_str; std::string customer_name; std::string customer_email; std::string order_ref; std::string serial_number; std::string comments; bool blocked = false; license_node->QueryStringAttribute("Date", &date_str); license_node->QueryStringAttribute("CustomerName", &customer_name); license_node->QueryStringAttribute("CustomerEmail", &customer_email); license_node->QueryStringAttribute("OrderRef", &order_ref); license_node->QueryStringAttribute("SerialNumber", &serial_number); license_node->QueryBoolAttribute("Blocked", &blocked); TiXmlElement *comments_node = license_node->FirstChildElement("Comments"); const char *str = comments_node ? comments_node->GetText() : license_node->GetText(); if (str) comments = std::string(str); Add(LicenseDate(atoi(date_str.substr(0, 4).c_str()), atoi(date_str.substr(5, 2).c_str()), atoi(date_str.substr(8, 2).c_str())), customer_name, customer_email, order_ref, comments, serial_number, blocked); license_node = license_node->NextSiblingElement("License"); } } } changed(); return true; } bool LicensingManager::Save() { if (file_name_.empty()) return false; TiXmlDocument doc; if (!doc.LoadFile(file_name_.c_str())) doc.LinkEndChild(new TiXmlDeclaration("1.0", "UTF-8", "")); TiXmlElement *root_node = doc.FirstChildElement("Document"); if (!root_node) { root_node = new TiXmlElement("Document"); doc.LinkEndChild(root_node); } TiXmlElement *license_manager_node = root_node->FirstChildElement("LicenseManager"); if (!license_manager_node) { license_manager_node = new TiXmlElement("LicenseManager"); root_node->LinkEndChild(license_manager_node); } else { license_manager_node->Clear(); } if (!product_code_.empty()) license_manager_node->SetAttribute("ProductCode", VectorToBase64(product_code_)); if (!activation_server_.empty()) license_manager_node->SetAttribute("ActivationServer", activation_server_); if (algorithm_ != alNone) { license_manager_node->SetAttribute("Algorithm", "RSA"); license_manager_node->SetAttribute("Bits", bits_); license_manager_node->SetAttribute("PublicExp", VectorToBase64(public_exp_)); license_manager_node->SetAttribute("PrivateExp", VectorToBase64(private_exp_)); license_manager_node->SetAttribute("Modulus", VectorToBase64(modulus_)); for (size_t i = 0; i < count(); i++) { License *license = item(i); TiXmlElement *license_node = new TiXmlElement("License"); license_manager_node->LinkEndChild(license_node); license_node->SetAttribute("Date", string_format("%.4d-%.2d-%.2d", license->date().Year, license->date().Month, license->date().Day)); if (!license->customer_name().empty()) license_node->SetAttribute("CustomerName", license->customer_name()); if (!license->customer_email().empty()) license_node->SetAttribute("CustomerEmail", license->customer_email()); if (!license->order_ref().empty()) license_node->SetAttribute("OrderRef", license->order_ref()); license_node->SetAttribute("SerialNumber", license->serial_number()); if (license->blocked()) license_node->SetAttribute("Blocked", license->blocked()); if (!license->comments().empty()) license_node->LinkEndChild(new TiXmlText(license->comments())); } } if (!doc.SaveFile(file_name_.c_str())) return false; return true; } bool LicensingManager::SaveAs(const std::string &file_name) { std::string old_file_name = file_name_; file_name_ = file_name; if (!Save()) { file_name_ = old_file_name; return false; } if (old_file_name != file_name_) changed(); return true; } License *LicensingManager::Add(LicenseDate date, const std::string &customer_name, const std::string &customer_email, const std::string &order_ref, const std::string &comments, const std::string &serial_number, bool blocked) { License *license = new License(this, date, customer_name, customer_email, order_ref, comments, serial_number, blocked); AddObject(license); return license; } uint64_t LicensingManager::product_code() const { uint64_t res = 0; if (!product_code_.empty()) memcpy(&res, &product_code_[0], std::min(product_code_.size(), sizeof(res))); return res; } std::vector LicensingManager::hash() const { std::vector res; if (!modulus_.empty()) { SHA1 sha; sha.Input(modulus_.data(), modulus_.size()); res.insert(res.end(), sha.Result(), sha.Result() + sha.ResultSize()); } return res; } enum SerialNumberChunks { SERIAL_CHUNK_VERSION = 0x01, // 1 byte of data - version SERIAL_CHUNK_USER_NAME = 0x02, // 1 + N bytes - length + N bytes of customer's name (without enging \0). SERIAL_CHUNK_EMAIL = 0x03, // 1 + N bytes - length + N bytes of customer's email (without ending \0). SERIAL_CHUNK_HWID = 0x04, // 1 + N bytes - length + N bytes of hardware id (N % 4 == 0) SERIAL_CHUNK_EXP_DATE = 0x05, // 4 bytes - (year << 16) + (month << 8) + (day) SERIAL_CHUNK_RUNNING_TIME_LIMIT = 0x06, // 1 byte - number of minutes SERIAL_CHUNK_PRODUCT_CODE = 0x07, // 8 bytes - used for decrypting some parts of exe-file SERIAL_CHUNK_USER_DATA = 0x08, // 1 + N bytes - length + N bytes of user data SERIAL_CHUNK_MAX_BUILD = 0x09, // 4 bytes - (year << 16) + (month << 8) + (day) SERIAL_CHUNK_END = 0xFF // 4 bytes - checksum: the first four bytes of sha-1 hash from the data before that chunk }; std::string LicensingManager::GenerateSerialNumber(const LicenseInfo &info) { if (algorithm_ == alNone) throw std::runtime_error(language[lsLicensingParametersNotInitialized]); Data data; data.PushByte(SERIAL_CHUNK_VERSION); data.PushByte(1); if (info.Flags & HAS_USER_NAME) { data.PushByte(SERIAL_CHUNK_USER_NAME); if (info.CustomerName.size() > 255) throw std::runtime_error(language[lsCustomerNameTooLong]); data.PushByte((uint8_t)info.CustomerName.size()); data.PushBuff(info.CustomerName.c_str(), info.CustomerName.size()); } if (info.Flags & HAS_EMAIL) { data.PushByte(SERIAL_CHUNK_EMAIL); if (info.CustomerEmail.size() > 255) throw std::runtime_error(language[lsEmailTooLong]); data.PushByte((uint8_t)info.CustomerEmail.size()); data.PushBuff(info.CustomerEmail.c_str(), info.CustomerEmail.size()); } if (info.Flags & HAS_HARDWARE_ID) { data.PushByte(SERIAL_CHUNK_HWID); std::vector hwid; Base64ToVector(info.HWID.c_str(), info.HWID.size(), hwid); if (!hwid.size() || hwid.size() > 255 || hwid.size() % 4 != 0) throw std::runtime_error(language[lsInvalidHWID]); data.PushByte((uint8_t)hwid.size()); data.PushBuff(&hwid[0], hwid.size()); } if (info.Flags & HAS_EXP_DATE) { data.PushByte(SERIAL_CHUNK_EXP_DATE); data.PushDWord(info.ExpireDate.value()); } if (info.Flags & HAS_TIME_LIMIT) { data.PushByte(SERIAL_CHUNK_RUNNING_TIME_LIMIT); data.PushByte(info.RunningTimeLimit); } if (product_code_.size() != 8) throw std::runtime_error(language[lsInvalidProductCode]); data.PushByte(SERIAL_CHUNK_PRODUCT_CODE); data.PushBuff(&product_code_[0], product_code_.size()); if (info.Flags & HAS_USER_DATA) { data.PushByte(SERIAL_CHUNK_USER_DATA); if (info.UserData.size() > 255) throw std::runtime_error(language[lsUserDataTooLong]); data.PushByte((uint8_t)info.UserData.size()); data.PushBuff(info.UserData.c_str(), info.UserData.size()); } if (info.Flags & HAS_MAX_BUILD_DATE) { data.PushByte(SERIAL_CHUNK_MAX_BUILD); data.PushDWord(info.MaxBuildDate.value()); } // compute hash { SHA1 sha; sha.Input(data.data(), data.size()); data.PushByte(SERIAL_CHUNK_END); const uint8_t *p = sha.Result(); for (size_t i = 0; i < 4; i++) { data.PushByte(p[3 - i]); } } // add padding size_t min_padding = 8 + 3; size_t max_padding = min_padding + 16; size_t max_bytes = bits_ / 8; if (data.size() + min_padding > max_bytes) throw std::runtime_error(language[lsSerialNumberTooLong]); srand(os::GetTickCount()); size_t padding_bytes = min_padding + rand() % (max_padding - min_padding); data.InsertBuff(0, data.data(), padding_bytes); data[0] = 0; data[1] = 2; data[padding_bytes - 1] = 0; for (size_t i = 2; i < padding_bytes - 1; i++) { uint8_t b = 0; while (!b) { b = rand(); } data[i] = b; } while (data.size() < max_bytes) { data.PushByte(rand()); } { RSA rsa(public_exp_, private_exp_, modulus_); if (!rsa.Encrypt(data)) throw std::runtime_error(language[lsSerialNumberTooLong]); } size_t len = Base64EncodeGetRequiredLength(data.size()); char *buffer = new char[len]; Base64Encode(data.data(), data.size(), buffer, len); std::string res = std::string(buffer, len); delete [] buffer; return res; } bool LicensingManager::DecryptSerialNumber(const std::string &serial_number, LicenseInfo &license_info) { if (serial_number.empty()) return false; size_t len = serial_number.size(); uint8_t *buffer = new uint8_t[len]; Base64Decode(serial_number.c_str(), serial_number.size(), buffer, len); Data data; data.PushBuff(buffer, len); delete [] buffer; { RSA rsa(public_exp_, private_exp_, modulus_); if (!rsa.Decrypt(data)) return false; } if (data.size() < (8 + 3 + 1 + 4) || data[0] != 0 || data[1] != 2) return false; size_t i; for (i = 2; i < data.size() && data[i] != 0; i++) { } i++; size_t pos = i; while (pos < data.size()) { uint8_t b = data[pos++]; switch (b) { case SERIAL_CHUNK_VERSION: b = data[pos++]; if (b < 1 || b > 2) return false; break; case SERIAL_CHUNK_USER_NAME: b = data[pos++]; license_info.CustomerName = std::string(reinterpret_cast(&data[pos]), b); license_info.Flags |= HAS_USER_NAME; pos += b; break; case SERIAL_CHUNK_EMAIL: b = data[pos++]; license_info.CustomerEmail = std::string(reinterpret_cast(&data[pos]), b); license_info.Flags |= HAS_EMAIL; pos += b; break; case SERIAL_CHUNK_HWID: b = data[pos++]; { size_t len = Base64EncodeGetRequiredLength(b); char *buffer = new char[len]; Base64Encode(&data[pos], b, buffer, len); license_info.HWID = std::string(buffer, len); delete [] buffer; } license_info.Flags |= HAS_HARDWARE_ID; pos += b; break; case SERIAL_CHUNK_EXP_DATE: license_info.ExpireDate = LicenseDate(data.ReadDWord(pos)); license_info.Flags |= HAS_EXP_DATE; pos += 4; break; case SERIAL_CHUNK_RUNNING_TIME_LIMIT: license_info.RunningTimeLimit = data[pos]; license_info.Flags |= HAS_TIME_LIMIT; pos++; break; case SERIAL_CHUNK_PRODUCT_CODE: pos += 8; break; case SERIAL_CHUNK_USER_DATA: b = data[pos++]; license_info.UserData = std::string(reinterpret_cast(&data[pos]), b); license_info.Flags |= HAS_USER_DATA; pos += b; break; case SERIAL_CHUNK_MAX_BUILD: license_info.MaxBuildDate = LicenseDate(data.ReadDWord(pos)); license_info.Flags |= HAS_MAX_BUILD_DATE; pos += 4; break; case SERIAL_CHUNK_END: if (pos + 4 > data.size()) return false; { SHA1 sha; sha.Input(&data[i], pos - i - 1); const uint8_t *p = sha.Result(); for (size_t j = 0; j < 4; j++) { if (data[pos + j] != p[3 - j]) return false; } } return true; } } return false; } License *LicensingManager::GetLicenseBySerialNumber(const std::string &serial_number) { std::vector binary_serial; Base64ToVector(serial_number.c_str(), serial_number.size(), binary_serial); SHA1 sha; sha.Input(&binary_serial[0], binary_serial.size()); const uint8_t *src = sha.Result(); uint8_t hash[20]; memcpy(hash, src, sizeof(hash)); for (size_t i = 0; i < count(); i++) { License *license = item(i); uint8_t license_hash[20]; license->GetHash(license_hash); if (memcmp(hash, license_hash, sizeof(hash)) == 0) return license; } return NULL; } bool LicensingManager::CompareParameters(const LicensingManager &manager) const { return (algorithm_ == alRSA && algorithm_ == manager.algorithm_ && bits_ == manager.bits_ && public_exp_ == manager.public_exp_ && private_exp_ == manager.private_exp_ && modulus_ == manager.modulus_ && product_code_ == manager.product_code_); } void LicensingManager::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } void LicensingManager::AddObject(License *license) { ObjectList::AddObject(license); Notify(mtAdded, license); } void LicensingManager::RemoveObject(License *license) { Notify(mtDeleted, license); ObjectList::RemoveObject(license); } /** * FileFolder */ FileFolder::FileFolder(FileFolder *owner, const std::string &name) : ObjectList(), owner_(owner), name_(name), entry_offset_(0) { } FileFolder::~FileFolder() { clear(); if (owner_) owner_->RemoveObject(this); Notify(mtDeleted, this); } FileFolder::FileFolder(FileFolder *owner, const FileFolder &src) : ObjectList(src), owner_(owner), entry_offset_(0) { name_ = src.name_; for (size_t i = 0; i < src.count(); i++) { AddObject(src.item(i)->Clone(this)); } } FileFolder *FileFolder::Clone(FileFolder *owner) const { FileFolder *folder = new FileFolder(owner, *this); return folder; } FileFolder *FileFolder::Add(const std::string &name) { FileFolder *folder = new FileFolder(this, name); AddObject(folder); Notify(mtAdded, folder); return folder; } void FileFolder::changed() { Notify(mtChanged, this); } std::string FileFolder::id() const { std::string res; const FileFolder *folder = this; while (folder->owner_) { res = res + string_format("\\%d", folder->owner_->IndexOf(folder)); folder = folder->owner_; } return res; } void FileFolder::set_name(const std::string &name) { if (name_ != name) { name_ = name; changed(); } } void FileFolder::set_owner(FileFolder *owner) { if (owner == owner_) return; if (owner_) owner_->RemoveObject(this); owner_ = owner; if (owner_) owner_->AddObject(this); changed(); } void FileFolder::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } FileFolder *FileFolder::GetFolderById(const std::string &id) const { if (this->id() == id) return (FileFolder *)this; for (size_t i = 0; i < count(); i++) { FileFolder *res = item(i)->GetFolderById(id); if (res) return res; } return NULL; } void FileFolder::WriteEntry(IFunction &func) { entry_offset_ = func.count(); func.AddCommand(osDWord, 0); func.AddCommand(osDWord, 0); func.AddCommand(osDWord, 0); func.AddCommand(osDWord, 0); } void FileFolder::WriteName(IFunction &func, uint64_t image_base, uint32_t key) { std::string full_name = name_; FileFolder *folder = owner_; while (folder && folder->owner()) { full_name = folder->name() + '\\' + full_name; folder = folder->owner(); } os::unicode_string unicode_name = os::FromUTF8(full_name); const os::unicode_char *p = unicode_name.c_str(); Data str; for (size_t i = 0; i < unicode_name.size() + 1; i++) { str.PushWord(static_cast(p[i] ^ (_rotl32(key, static_cast(i)) + i))); } ICommand *command = func.AddCommand(str); command->include_option(roCreateNewBlock); CommandLink *link = func.item(entry_offset_)->AddLink(0, ltOffset, command); link->set_sub_value(image_base); } /** * FileFolderList */ FileFolderList::FileFolderList(FileManager *owner) : FileFolder(NULL, ""), owner_(owner) { } FileFolderList::FileFolderList(FileManager *owner, const FileFolderList & /*src*/) : FileFolder(NULL, ""), owner_(owner) { } FileFolderList *FileFolderList::Clone(FileManager *owner) const { FileFolderList *list = new FileFolderList(owner, *this); return list; } std::vector FileFolderList::GetFolderList() const { std::vector res; FileFolder *folder; size_t i, j; for (i = 0; i < count(); i++) { res.push_back(item(i)); } for (i = 0; i < res.size(); i++) { folder = res[i]; for (j = 0; j < folder->count(); j++) { res.push_back(folder->item(j)); } } return res; } void FileFolderList::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) { if (type == mtDeleted) { for (size_t i = owner_->count(); i > 0; i--) { InternalFile *file = owner_->item(i - 1); if (file->folder() == sender) delete file; } } owner_->Notify(type, sender, message); } } /** * InternalFile */ InternalFile::InternalFile(FileManager *owner, const std::string &name, const std::string &file_name, InternalFileAction action, FileFolder *folder) : owner_(owner), name_(name), file_name_(file_name), action_(action), stream_(NULL), entry_offset_(0), folder_(folder) { } InternalFile::~InternalFile() { Close(); if (owner_) owner_->RemoveObject(this); Notify(mtDeleted, this); } void InternalFile::set_name(const std::string &value) { if (name_ != value) { name_ = value; Notify(mtChanged, this); } } void InternalFile::set_file_name(const std::string &value) { if (file_name_ != value) { file_name_ = value; Notify(mtChanged, this); } } void InternalFile::set_action(InternalFileAction action) { if (action_ != action) { action_ = action; Notify(mtChanged, this); } } void InternalFile::set_folder(FileFolder *folder) { if (folder_ != folder) { folder_ = folder; Notify(mtChanged, this); } } size_t InternalFile::id() const { return owner_->IndexOf(this); } void InternalFile::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } std::string InternalFile::absolute_file_name() const { std::string project_path = owner_ ? owner_->owner()->project_path() : std::string(); return os::CombinePaths(project_path.c_str(), os::ExpandEnvironmentVariables(file_name_.c_str()).c_str()); } bool InternalFile::Open() { Close(); std::string file_name = absolute_file_name(); FileStream *stream = new FileStream(); if (stream->Open(file_name.c_str(), fmOpenRead | fmShareDenyWrite)) { stream_ = stream; } else { delete stream; Notify(mtError, this, string_format(language[lsOpenFileError].c_str(), file_name.c_str())); } return stream_ != NULL; } void InternalFile::Close() { if (stream_) { delete stream_; stream_ = NULL; } } void InternalFile::WriteEntry(IFunction &func) { entry_offset_ = func.count(); func.AddCommand(osDWord, 0); func.AddCommand(osDWord, 0); func.AddCommand(osDWord, stream_->Size()); uint32_t value; switch (action_) { case faLoad: value = FILE_LOAD; break; case faRegister: value = FILE_REGISTER; break; case faInstall: value = FILE_INSTALL; break; default: value = 0; break; } func.AddCommand(osDWord, value); } void InternalFile::WriteName(IFunction &func, uint64_t image_base, uint32_t key) { std::string full_name = name_; FileFolder *folder = folder_; while (folder && folder->owner()) { full_name = folder->name() + '\\' + full_name; folder = folder->owner(); } os::unicode_string unicode_name = os::FromUTF8(full_name); const os::unicode_char *p = unicode_name.c_str(); Data str; for (size_t i = 0; i < unicode_name.size() + 1; i++) { str.PushWord(static_cast(p[i] ^ (_rotl32(key, static_cast(i)) + i))); } ICommand *command = func.AddCommand(str); command->include_option(roCreateNewBlock); CommandLink *link = func.item(entry_offset_)->AddLink(0, ltOffset, command); link->set_sub_value(image_base); } void InternalFile::WriteData(IFunction &func, uint64_t image_base, uint32_t key) { std::vector buf; buf.resize(static_cast(stream_->Size())); stream_->Read(&buf[0], buf.size()); Data d; for (size_t i = 0; i < buf.size(); i++) { d.PushByte(buf[i] ^ static_cast(_rotl32(key, static_cast(i)) + i)); } ICommand *command = func.AddCommand(d); command->include_option(roCreateNewBlock); CommandLink *link = func.item(entry_offset_ + 1)->AddLink(0, ltOffset, command); link->set_sub_value(image_base); } /** * FileManager */ FileManager::FileManager(Core *owner) : ObjectList(), owner_(owner), need_compile_(true) { folder_list_ = new FileFolderList(this); } FileManager::~FileManager() { delete folder_list_; } void FileManager::clear() { ObjectList::clear(); folder_list_->clear(); } InternalFile *FileManager::Add(const std::string &name, const std::string &file_name, InternalFileAction action, FileFolder *folder) { InternalFile *file = new InternalFile(this, name, file_name, action, folder); AddObject(file); Notify(mtAdded, file); return file; } bool FileManager::OpenFiles() { bool res = true; for (size_t i = 0; i < count(); i++) { InternalFile *file = item(i); if (!file->Open()) { res = false; break; } } if (!res) CloseFiles(); return res; } void FileManager::CloseFiles() { for (size_t i = 0; i < count(); i++) { InternalFile *file = item(i); file->Close(); } } void FileManager::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } void FileManager::set_need_compile(bool need_compile) { if (need_compile_ != need_compile) { need_compile_ = need_compile; Notify(mtChanged, this); } } uint32_t FileManager::GetRuntimeOptions() const { if (!count()) return roNone; uint32_t res = roBundler; if (server_count()) res |= roRegistry; return res; } size_t FileManager::server_count() const { size_t res = 0; for (size_t i = 0; i < count(); i++) { if (item(i)->is_server()) res++; } return res; } #endif /** * RSA */ RSA::RSA() { private_exp_ = new BigNumber(); public_exp_ = new BigNumber(); modulus_ = new BigNumber(); } RSA::RSA(const std::vector &public_exp, const std::vector &private_exp, const std::vector &modulus) { private_exp_ = new BigNumber(private_exp.data(), private_exp.size()); public_exp_ = new BigNumber(public_exp.data(), public_exp.size()); modulus_ = new BigNumber(modulus.data(), modulus.size()); } RSA::~RSA() { delete private_exp_; delete public_exp_; delete modulus_; } bool RSA::Encrypt(Data &data) { if (!private_exp_->size() || !modulus_->size()) return false; BigNumber x(data.data(), data.size()); if (*modulus_ < x) return false; BigNumber y = x.modpow(*private_exp_, *modulus_); size_t len = y.size(); data.resize(len); for (size_t i = 0; i < len; i++) { data[i] = y[len - 1 - i]; } return true; } bool RSA::Decrypt(Data &data) { if (!public_exp_->size() || !modulus_->size()) return false; BigNumber x(data.data(), data.size()); if (*modulus_ < x) return false; BigNumber y = x.modpow(*public_exp_, *modulus_); size_t len = y.size(); data.resize(len); for (size_t i = 0; i < len; i++) { data[i] = y[len - 1 - i]; } return true; } static std::vector bignum_to_vector(const BigNumber &value) { std::vector res; size_t len = value.size(); res.resize(len); for (size_t i = 0; i < len; i++) { res[i] = value[len - 1 - i]; } return res; } std::vector RSA::public_exp() const { return bignum_to_vector(*public_exp_); } std::vector RSA::private_exp() const { return bignum_to_vector(*private_exp_); } std::vector RSA::modulus() const { return bignum_to_vector(*modulus_); } #ifdef __APPLE__ static const uint8_t *BerForward(const uint8_t *curPtr, size_t *len) { if(*curPtr++ != 0x02) return NULL; // only INTEGER accepted *len = *curPtr++; if(*len > 0x80) { int sizeOctets = *len & 0x7F; *len = 0; while(sizeOctets--) { *len = *len * 0x100 + *curPtr++; } } return curPtr; } #endif bool RSA::CreateKeyPair(size_t key_length) { bool res = false; #ifdef __unix__ OpenSSL::BIGNUM *bne = OpenSSL::BN_new(); if (OpenSSL::BN_set_word(bne, RSA_F4) == 1) { OpenSSL::RSA *r = OpenSSL::RSA_new(); if (OpenSSL::RSA_generate_key_ex(r, key_length, bne, NULL) == 1) { delete private_exp_; delete public_exp_; delete modulus_; bool bInv = false; uint8_t *data = new uint8_t[key_length / 8 + 1]; OpenSSL::BN_bn2bin(r->n, data); modulus_ = new BigNumber(data, BN_num_bytes(r->n), bInv); OpenSSL::BN_bn2bin(r->e, data); public_exp_ = new BigNumber(data, BN_num_bytes(r->e), bInv); OpenSSL::BN_bn2bin(r->d, data); private_exp_ = new BigNumber(data, BN_num_bytes(r->d), bInv); delete data; res = true; } OpenSSL::RSA_free(r); } OpenSSL::BN_free(bne); #elif defined(__APPLE__) CFMutableDictionaryRef parameters = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA); int rawnum = key_length; CFNumberRef num = CFNumberCreate( NULL, kCFNumberIntType, &rawnum); CFDictionarySetValue( parameters, kSecAttrKeySizeInBits, num); // Keychain Access tool should display our items as VMProtect XXX, no (if it was not deleted) std::ostringstream stringStream; stringStream << "VMProtect " << rand(); CFStringRef name = CFStringCreateWithCString(NULL, stringStream.str().c_str(), kCFStringEncodingUTF8); CFDictionarySetValue( parameters, kSecAttrLabel, name); SecKeyRef publickey, privatekey; //http://stackoverflow.com/questions/11206327/secitemexport-fails-when-exporting-private-key OSStatus status = SecKeyGeneratePair(parameters, &publickey, &privatekey); #ifdef CHECKED std::cout << "SecKeyGeneratePair(...) = " << status << std::endl; #endif if (status == errSecSuccess) { int bytes_in_key = key_length / 8; CFDataRef priv; status = SecItemExport(privatekey, kSecFormatUnknown, 0, NULL, &priv); //PKCS#1 if(status == errSecSuccess) { #ifdef CHECKED std::cout << "SecItemExport(...) = " << status << std::endl; #endif const uint8_t *privBytes = CFDataGetBytePtr(priv); size_t length = CFDataGetLength(priv); if(privBytes[0] == 0x30 && // signature privBytes[4] == 0x02 && privBytes[5] == 0x01 && privBytes[6] == 0x00) // version = 0 { #ifdef CHECKED std::cout << "signature OK" << std::endl; #endif size_t modulus_len, public_exp_len, private_exp_len; const uint8_t *modulus_bytes = BerForward(privBytes + 7, &modulus_len); if(modulus_bytes) { #ifdef CHECKED std::cout << "modulus found" << std::endl; #endif const uint8_t *public_exp_bytes = BerForward(modulus_bytes + modulus_len, &public_exp_len); if(public_exp_bytes) { #ifdef CHECKED std::cout << "public found" << std::endl; #endif const uint8_t *private_exp_bytes = BerForward(public_exp_bytes + public_exp_len, &private_exp_len); if(private_exp_bytes) { #ifdef CHECKED std::cout << "private found" << std::endl; #endif delete private_exp_; delete public_exp_; delete modulus_; bool bInv = false; modulus_ = new BigNumber(modulus_bytes, modulus_len, bInv); public_exp_ = new BigNumber(public_exp_bytes, public_exp_len, bInv); private_exp_ = new BigNumber(private_exp_bytes, private_exp_len, bInv); res = true; } } } CFRelease(priv); } } // do not waste system: delete key pair CFMutableDictionaryRef attrDict = CFDictionaryCreateMutable(NULL, 4, &kCFTypeDictionaryKeyCallBacks, NULL); CFDictionaryAddValue(attrDict, kSecClass, kSecClassKey); CFDictionaryAddValue(attrDict, kSecAttrKeyType, kSecAttrKeyTypeRSA); CFDictionaryAddValue(attrDict, kSecAttrLabel, name); CFDictionaryAddValue(attrDict, kSecMatchLimit, kSecMatchLimitAll); SecItemDelete(attrDict); CFRelease(attrDict); CFRelease(publickey); CFRelease(privatekey); } CFRelease(num); CFRelease(name); CFRelease(parameters); #else struct {LPCWSTR name; DWORD type;} providers[] = // structure of providers names and types. we'll try them one by one until they end or we'll find one that works { {MS_STRONG_PROV, PROV_RSA_FULL}, {NULL, PROV_RSA_FULL}, {NULL, PROV_RSA_SCHANNEL}, {NULL, PROV_RSA_AES}, }; for (size_t i = 0; i < _countof(providers) && !res; i++) { HCRYPTPROV prov; if (CryptAcquireContext(&prov, NULL, providers[i].name, providers[i].type, CRYPT_VERIFYCONTEXT)) { HCRYPTKEY key; if (CryptGenKey(prov, CALG_RSA_KEYX, MAKELONG(CRYPT_EXPORTABLE, key_length), &key)) { DWORD len = (DWORD)(key_length * 2); uint8_t *data = new uint8_t[len]; memset(data, 0, len); if (CryptExportKey(key, NULL, PRIVATEKEYBLOB, 0, data, &len)) { BLOBHEADER *header = reinterpret_cast(data); if ((header->aiKeyAlg & ALG_TYPE_RSA) == ALG_TYPE_RSA) { RSAPUBKEY *rsa_key = reinterpret_cast(data + sizeof(BLOBHEADER)); if (rsa_key->magic == 0x32415352 && rsa_key->bitlen == key_length) { // RSA2 delete private_exp_; delete public_exp_; delete modulus_; int bytes_in_key = rsa_key->bitlen / 8; public_exp_ = new BigNumber(reinterpret_cast(&rsa_key->pubexp), 4, true); private_exp_ = new BigNumber(data + len - bytes_in_key, bytes_in_key, true); modulus_ = new BigNumber(data + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), bytes_in_key, true); res = true; } } } delete [] data; } } } #endif return res; } /** * ProjectTemplateManager */ ProjectTemplateManager::ProjectTemplateManager(Core *owner) : ObjectList(), owner_(owner) { ProjectTemplate *pt = new ProjectTemplate(this, ProjectTemplate::default_name(), true); AddObject(pt); } void ProjectTemplateManager::ReadFromFile(SettingsFile &file) { TiXmlElement *node = file.root_node(); TiXmlElement *templates_node = node->FirstChildElement("Templates"); if (templates_node) { TiXmlElement *template_node = templates_node->FirstChildElement("Template"); while (template_node) { std::string name; template_node->QueryStringAttribute("Name", &name); ProjectTemplate *pt; if (name == ProjectTemplate::default_name()) pt = item(0); else { pt = new ProjectTemplate(this, name); AddObject(pt); } pt->ReadFromNode(template_node); template_node = template_node->NextSiblingElement(); } } } void ProjectTemplateManager::SaveToFile(SettingsFile &file) const { TiXmlElement *node = file.root_node(); TiXmlElement *templates_node = node->FirstChildElement("Templates"); if (!templates_node) { templates_node = new TiXmlElement("Templates"); node->LinkEndChild(templates_node); } else { templates_node->Clear(); } for (size_t i = 0; i < count(); i++) { TiXmlElement *template_node = new TiXmlElement("Template"); templates_node->LinkEndChild(template_node); template_node->SetAttribute("Name", item(i)->name()); item(i)->SaveToNode(template_node); } file.Save(); } void ProjectTemplateManager::Add(const std::string &name, const Core &core) { ProjectTemplate *pt = NULL; if (name == item(0)->display_name()) pt = item(0); else for (size_t i = 0; i < count(); i++) { if (item(i)->name() == name) { pt = item(i); break; } } if (!pt) { pt = new ProjectTemplate(this, name); AddObject(pt); Notify(mtAdded, pt); } pt->ReadFromCore(core); } void ProjectTemplateManager::Notify(MessageType type, IObject *sender, const std::string &message) const { if (owner_) owner_->Notify(type, sender, message); } void ProjectTemplateManager::RemoveObject(ProjectTemplate *pt) { ObjectList::RemoveObject(pt); Notify(mtDeleted, pt); } /** * ProjectTemplate */ ProjectTemplate::ProjectTemplate(ProjectTemplateManager *owner, const std::string &name, bool is_default) : IObject(), owner_(owner), name_(name), options_(0), is_default_(is_default) { Init(); } ProjectTemplate::~ProjectTemplate() { if (owner_) owner_->RemoveObject(this); } void ProjectTemplate::ReadFromNode(TiXmlElement *node) { unsigned u = options_; node->QueryUnsignedAttribute("Options", &u); options_ = u; bool check_kernel_debugger = false; node->QueryBoolAttribute("CheckKernelDebugger", &check_kernel_debugger); if (check_kernel_debugger) options_ |= cpCheckKernelDebugger; node->QueryStringAttribute("VMCodeSectionName", &vm_section_name_); TiXmlElement *messages_node = node->FirstChildElement("Messages"); if (messages_node) { TiXmlElement *message_node = messages_node->FirstChildElement("Message"); while (message_node) { u = 0; message_node->QueryUnsignedAttribute("Id", &u); if (u < _countof(messages_)) { if (const char *text = message_node->GetText()) messages_[u] = text; else messages_[u].clear(); } message_node = message_node->NextSiblingElement(message_node->Value()); } } } void ProjectTemplate::ReadFromCore(const Core &core) { options_ = core.options(); vm_section_name_ = core.vm_section_name(); for (size_t i = 0; i < _countof(messages_); i++) { messages_[i] = core.message(i); } Notify(mtChanged, this); } void ProjectTemplate::SaveToNode(TiXmlElement *node) const { node->SetAttribute("Options", options_); node->SetAttribute("VMCodeSectionName", vm_section_name_); TiXmlElement *messages_node = node->FirstChildElement("Messages"); if (!messages_node) { messages_node = new TiXmlElement("Messages"); node->LinkEndChild(messages_node); } else { messages_node->Clear(); } for (size_t i = 0; i < _countof(messages_); i++) { const std::string &message = messages_[i]; if (message != #ifdef VMP_GNU default_message[i] #else os::ToUTF8(default_message[i]) #endif ) { TiXmlElement *message_node = new TiXmlElement("Message"); messages_node->LinkEndChild(message_node); message_node->SetAttribute("Id", (int)i); message_node->LinkEndChild(new TiXmlText(message)); } } } void ProjectTemplate::Init() { options_ = cpMaximumProtection; // create random section name vm_section_name_ = "."; size_t i; static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; srand(os::GetTickCount()); for (i = 0; i < 3; i++) { vm_section_name_ += alphanum[rand() % (sizeof(alphanum) - 1)]; } for (i = 0; i < _countof(messages_); i++) { #ifdef VMP_GNU messages_[i] = default_message[i]; #else messages_[i] = os::ToUTF8(default_message[i]); #endif } } void ProjectTemplate::Reset() { Init(); Notify(mtChanged, this); } bool ProjectTemplate::operator==(const ProjectTemplate &other) const { if (options_ != other.options_) return false; if (vm_section_name_ != other.vm_section_name_) return false; for (size_t i = 0; i < _countof(messages_); i++) { if(messages_[i] != other.messages_[i]) return false; } return true; } std::string ProjectTemplate::display_name() const { return is_default_ ? "(" + language[lsDefault] + ")" : name_; } std::string ProjectTemplate::message(size_t idx) const { if (idx >= _countof(messages_)) throw std::runtime_error("subscript out of range"); return messages_[idx]; } void ProjectTemplate::Notify(MessageType type, IObject *sender, const std::string &message /*= ""*/) const { if (owner_) owner_->Notify(type, sender, message); } void ProjectTemplate::set_name(const std::string &name) { if (name != name_) { name_ = name; Notify(mtChanged, this); } }