3625 lines
100 KiB
C++
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);
|
|
}
|
|
} |