VMProtect/core/core.cc

3625 lines
100 KiB
C++

#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);
}
}