aboutsummaryrefslogtreecommitdiff
path: root/runtime/string_manager.cc
blob: e49d568f467da321210d45b6f4af8161a2f38e46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include "objects.h"
#include "common.h"
#include "core.h"
#include "crypto.h"
#include "string_manager.h"

/**
 * exported functions
 */

#ifdef VMP_GNU
EXPORT_API const void * WINAPI ExportedDecryptString(const void *str) __asm__ ("ExportedDecryptString");
EXPORT_API bool WINAPI ExportedFreeString(const void *str) __asm__ ("ExportedFreeString");
#endif

const void * WINAPI ExportedDecryptString(const void *str)
{
	StringManager *string_manager = Core::Instance()->string_manager();
	return string_manager ? string_manager->DecryptString(str) : str;
}

bool WINAPI ExportedFreeString(const void *str)
{
	StringManager *string_manager = Core::Instance()->string_manager();
	return string_manager ? string_manager->FreeString(str) : false;
}

/**
 * StringManager
 */

StringManager::StringManager(const uint8_t *data, HMODULE instance, const uint8_t *key)
	: data_(data), instance_(instance)
{
	CriticalSection::Init(critical_section_);
	key_ = *(reinterpret_cast<const uint32_t *>(key));
	const STRING_DIRECTORY *directory_enc = reinterpret_cast<const STRING_DIRECTORY *>(data_);
	STRING_DIRECTORY directory = DecryptDirectory(directory_enc);
	size_ = directory.NumberOfEntries;
	strings_ = new VirtualString*[size_];
	memset(strings_, 0, sizeof(VirtualString *) * size_);
}

StringManager::~StringManager()
{
	for (size_t i = 0; i < size_; i++) {
		delete strings_[i];
	}
	delete [] strings_;
	CriticalSection::Free(critical_section_);
}

STRING_DIRECTORY StringManager::DecryptDirectory(const STRING_DIRECTORY *directory_enc) const
{
	STRING_DIRECTORY res;
	res.NumberOfEntries = directory_enc->NumberOfEntries ^ key_;
	return res;
}

STRING_ENTRY StringManager::DecryptEntry(const STRING_ENTRY *entry_enc) const
{
	STRING_ENTRY res;
	res.Id = entry_enc->Id ^ key_;
	res.OffsetToData = entry_enc->OffsetToData ^ key_;
	res.Size = entry_enc->Size ^ key_;
	return res;
}

size_t StringManager::IndexById(uint32_t id) const
{
	const STRING_ENTRY *entry_enc = reinterpret_cast<const STRING_ENTRY *>(data_ + sizeof(STRING_DIRECTORY));

	int min = 0;
	int max = (int)size_ - 1;
	while (min <= max) {
		int i = (min + max) / 2;
		STRING_ENTRY entry = DecryptEntry(entry_enc + i);
		if (entry.Id == id) {
			return i;
		}
		if (entry.Id > id) {
			max = i - 1;
		} else {
			min = i + 1;
		}
	}
	return NOT_ID;
}

const void *StringManager::DecryptString(const void *str)
{
	size_t id = reinterpret_cast<size_t>(str) - reinterpret_cast<size_t>(instance_);
	if ((id >> 31) == 0) {
		size_t i = IndexById(static_cast<uint32_t>(id));
		if (i != NOT_ID) {
			CriticalSection cs(critical_section_);
			VirtualString *string = strings_[i];
			if (!string) {
				const STRING_ENTRY *entry_enc = reinterpret_cast<const STRING_ENTRY *>(data_ + sizeof(STRING_DIRECTORY));
				string = new VirtualString(entry_enc + i, instance_, key_);
				strings_[i] = string;
			}
			return string->AcquirePointer();
		}
	}
	return str;
}

size_t StringManager::IndexByAddress(const void *address) const
{
	for (size_t i = 0; i < size_; i++) {
		VirtualString *string = strings_[i];
		if (string && string->address() == address)
			return i;
	}
	return NOT_ID;
}

bool StringManager::FreeString(const void *str)
{
	CriticalSection cs(critical_section_);

	size_t i = IndexByAddress(str);
	if (i == NOT_ID)
		return false;

	VirtualString *string = strings_[i];
	if (string->Release()) {
		delete string;
		strings_[i] = NULL;
	}
	return true;
}

/**
 * VirtualString
 */

VirtualString::VirtualString(const STRING_ENTRY *entry_enc, HMODULE instance, uint32_t key)
	: use_count_(0)
{
	STRING_ENTRY entry;
	entry.Id = entry_enc->Id ^ key;
	entry.OffsetToData = entry_enc->OffsetToData ^ key;
	entry.Size = entry_enc->Size ^ key;

	size_ = entry.Size;
	address_ = new uint8_t[size_];
	uint8_t *source = reinterpret_cast<uint8_t *>(instance) + entry.OffsetToData;
	for (size_t i = 0; i < size_; i++) {
		address_[i] = static_cast<uint8_t>(source[i] ^ (_rotl32(key, static_cast<int>(i)) + i));
	}
}

VirtualString::~VirtualString()
{
	Clear();
}

void VirtualString::Clear()
{
	if (address_) {
		volatile uint8_t *ptrSecureZeroing = address_;
		while (size_--) *ptrSecureZeroing++ = 0;
		delete [] address_;
		address_ = NULL;
	}
}

uint8_t *VirtualString::AcquirePointer()
{
	use_count_++;
	return address_;
}

bool VirtualString::Release()
{
	use_count_--;
	if (use_count_)
		return false;

	Clear();
	return true;
}