aboutsummaryrefslogtreecommitdiff
path: root/core/core.cc
diff options
context:
space:
mode:
Diffstat (limited to 'core/core.cc')
-rw-r--r--core/core.cc3625
1 files changed, 3625 insertions, 0 deletions
diff --git a/core/core.cc b/core/core.cc
new file mode 100644
index 0000000..8f85db8
--- /dev/null
+++ b/core/core.cc
@@ -0,0 +1,3625 @@
+#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 <Security/SecKey.h>
+#include <Security/SecItem.h>
+#include <Security/SecImportExport.h>
+#endif // __APPLE__
+
+#ifdef __unix__
+namespace OpenSSL {
+ #include <openssl/rsa.h>
+}
+#endif //__unix__
+
+void Base64ToVector(const char *src, size_t src_len, std::vector<uint8_t> &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<uint8_t> &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<Watermark>(), 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<Watermark>::RemoveObject(watermark);
+}
+
+void WatermarkManager::ReadFromIni(const std::string &file_name)
+{
+ IniFile file(file_name.c_str());
+ std::vector<std::string> 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<IFile> file[] = { std::auto_ptr<IFile>(new PEFile(log_)), std::auto_ptr<IFile>(new MacFile(log_)),
+ std::auto_ptr<IFile>(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 *> 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<uint64_t> 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<CompilationType>(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<AddressInfo> 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<FileFolder *> 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 *> 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::vector<uint64_t >address_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<CompilationType>(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*> 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<Folder*>::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<Data, std::map<IArchitecture*, std::vector<IFunction*> > > function_map;
+ std::map<IFunction*, size_t> 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<Data, std::map<IArchitecture*, std::vector<IFunction*> > >::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<Data, std::map<IArchitecture*, std::vector<IFunction*> > >::iterator it = function_map.begin(); it != function_map.end(); it++) {
+ for (std::map<IArchitecture*, std::vector<IFunction*> >::iterator arch_it = it->second.begin(); arch_it != it->second.end(); arch_it++) {
+ IArchitecture *arch = arch_it->first;
+ std::vector<uint64_t> 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<uint64_t>::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<IFunction*, size_t>::iterator index_it = function_index.find(function);
+ if (index_it == function_index.end())
+ continue;
+
+ map_index = index_it->second;
+ std::map<Data, std::map<IArchitecture*, std::vector<IFunction*> > >::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<size_t> source_index_list;
+ for (std::map<IArchitecture*, std::vector<IFunction*> >::iterator arch_it = it->second.begin(); arch_it != it->second.end(); arch_it++) {
+ std::vector<size_t> 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<Folder*>::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<int>(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<int>(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<Data, size_t> segment_map;
+ std::map<Data, size_t> resource_map;
+ std::map<Data, size_t> 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<Data, size_t>::iterator it = segment_map.find(hash);
+ if (it == segment_map.end())
+ segment_map[hash] = 1;
+ else
+ it->second++;
+ }
+
+ if (arch->resource_list()) {
+ std::vector<IResource*> 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<Data, size_t>::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<Data, size_t>::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<Data, size_t>::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<IResource*> 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<Data, size_t>::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<Data, size_t>::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<FileFolder*> 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<FileFolder*>::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<FileFolder*>::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<uint32_t>(output_file_->size());
+ EndCompileTransaction(locked_file, res);
+ if (res) {
+ Notify(mtInformation, NULL, string_format(
+ language[lsOutputFileSize].c_str(),
+ output_file_size,
+ static_cast<int>(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<Watermark *>(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<ProjectTemplate *>(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<uint8_t> 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<License>(), owner_(owner), algorithm_(alNone), bits_(0), build_date_(0)
+{
+
+}
+
+void LicensingManager::clear()
+{
+ ObjectList<License>::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<std::vector<uint8_t> > 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<uint8_t>(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<uint32_t>(data.size()));
+ data.WriteDWord(FIELD_PUBLIC_EXP_SIZE * sizeof(uint32_t), static_cast<uint32_t>(public_exp_.size()));
+ data.PushBuff(public_exp_.data(), public_exp_.size());
+
+ data.WriteDWord(FIELD_MODULUS_OFFSET * sizeof(uint32_t), static_cast<uint32_t>(data.size()));
+ data.WriteDWord(FIELD_MODULUS_SIZE * sizeof(uint32_t), static_cast<uint32_t>(modulus_.size()));
+ data.PushBuff(modulus_.data(), modulus_.size());
+
+ data.WriteDWord(FIELD_BLACKLIST_OFFSET * sizeof(uint32_t), static_cast<uint32_t>(data.size()));
+ data.WriteDWord(FIELD_BLACKLIST_SIZE * sizeof(uint32_t), static_cast<uint32_t>(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<uint32_t>(data.size()));
+ data.WriteDWord(FIELD_ACTIVATION_URL_SIZE * sizeof(uint32_t), static_cast<uint32_t>(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<uint32_t>(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<uint8_t> LicensingManager::hash() const
+{
+ std::vector<uint8_t> 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<uint8_t> 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<char *>(&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<char *>(&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<char *>(&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<uint8_t> 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<License>::AddObject(license);
+ Notify(mtAdded, license);
+}
+
+void LicensingManager::RemoveObject(License *license)
+{
+ Notify(mtDeleted, license);
+ ObjectList<License>::RemoveObject(license);
+}
+
+/**
+ * FileFolder
+ */
+
+FileFolder::FileFolder(FileFolder *owner, const std::string &name)
+ : ObjectList<FileFolder>(), 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<FileFolder>(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<uint16_t>(p[i] ^ (_rotl32(key, static_cast<int>(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<FileFolder*> FileFolderList::GetFolderList() const
+{
+ std::vector<FileFolder*> 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<uint16_t>(p[i] ^ (_rotl32(key, static_cast<int>(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<uint8_t> buf;
+ buf.resize(static_cast<size_t>(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<uint8_t>(_rotl32(key, static_cast<int>(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<InternalFile>(), owner_(owner), need_compile_(true)
+{
+ folder_list_ = new FileFolderList(this);
+}
+
+FileManager::~FileManager()
+{
+ delete folder_list_;
+}
+
+void FileManager::clear()
+{
+ ObjectList<InternalFile>::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<uint8_t> &public_exp, const std::vector<uint8_t> &private_exp, const std::vector<uint8_t> &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<uint8_t> bignum_to_vector(const BigNumber &value)
+{
+ std::vector<uint8_t> 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<uint8_t> RSA::public_exp() const
+{
+ return bignum_to_vector(*public_exp_);
+}
+
+std::vector<uint8_t> RSA::private_exp() const
+{
+ return bignum_to_vector(*private_exp_);
+}
+
+std::vector<uint8_t> 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 <key> (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<BLOBHEADER *>(data);
+ if ((header->aiKeyAlg & ALG_TYPE_RSA) == ALG_TYPE_RSA) {
+ RSAPUBKEY *rsa_key = reinterpret_cast<RSAPUBKEY *>(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<uint8_t *>(&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<ProjectTemplate>(), 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<ProjectTemplate>::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);
+ }
+} \ No newline at end of file