VMProtect/core/streams.cc

491 lines
9.4 KiB
C++

/**
* Stream implementation.
*/
#include "../runtime/crypto.h"
#include "objects.h"
#include "osutils.h"
#include "streams.h"
/**
* AbstractStream
*/
size_t AbstractStream::CopyFrom(AbstractStream &source, size_t count)
{
size_t copied_size, n, nc, total;
#define BUF_SIZE 4096 /* Let's use page size */
uint8_t buf[BUF_SIZE];
total = 0; /* Total copied */
for (n = 0; n < count; n += BUF_SIZE) {
nc = BUF_SIZE; /* Number of bytes to copy */
if (count - n < BUF_SIZE)
nc = count - n;
copied_size = source.Read(buf, nc);
if (copied_size)
Write(buf, copied_size);
total += copied_size;
if (nc != copied_size)
break;
}
Flush();
return total;
}
uint64_t AbstractStream::Tell()
{
return Seek(0, soCurrent);
}
uint64_t AbstractStream::Size()
{
uint64_t pos = Tell();
uint64_t size = Seek(0, soEnd);
/* Restore previous position */
Seek(pos, soBeginning);
return size;
}
/*static __inline bool IsCrLf(char c)
{
return c == '\r' || c == '\n';
}*/
/**
* MemoryStream
*/
MemoryStream::MemoryStream(size_t /*buf_size_increment*/)
: pos_(0)/*, buf_size_inc_(buf_size_increment)*/
{
}
size_t MemoryStream::Read(void *buffer, size_t size)
{
if (pos_ + size > buf_.size())
size = buf_.size() - pos_;
if (size) {
memcpy(buffer, &buf_[pos_], size);
pos_ += size;
}
return size;
}
uint64_t MemoryStream::Resize(uint64_t new_size)
{
buf_.resize(static_cast<size_t>(new_size));
pos_ = buf_.size();
return new_size;
}
size_t MemoryStream::Write(const void *buffer, size_t size)
{
if (size) {
if (pos_ + size > buf_.size())
buf_.resize(pos_ + size);
memcpy(&buf_[pos_], buffer, size);
pos_ += size;
}
return size;
}
uint64_t MemoryStream::Seek(int64_t offset, SeekOrigin origin)
{
intptr_t req_pos;
req_pos = static_cast<intptr_t>(offset);
switch (origin) {
case soBeginning:
break;
case soCurrent:
req_pos += pos_;
break;
case soEnd:
req_pos += buf_.size();
break;
default:
return -1;
}
pos_ = req_pos;
return pos_;
}
/**
* MemoryStreamEnc
*/
MemoryStreamEnc::MemoryStreamEnc(const void *buffer, size_t size, uint32_t key)
: MemoryStream(), key_(key)
{
MemoryStream::Write(buffer, size);
}
size_t MemoryStreamEnc::Read(void *buffer, size_t size)
{
uint64_t pos = Seek(0, soCurrent);
size_t res = MemoryStream::Read(buffer, size);
for (size_t i = 0; i < res; i++) {
int p = static_cast<int>(pos + i);
reinterpret_cast<uint8_t *>(buffer)[i] ^= static_cast<uint8_t>(_rotl32(key_, p) + p);
}
return res;
}
size_t MemoryStreamEnc::Write(const void *buffer, size_t size)
{
size_t res;
if (size) {
uint64_t pos = Seek(0, soCurrent);
uint8_t *enc_buffer = new uint8_t[size];
for (size_t i = 0; i < size; i++) {
int p = static_cast<int>(pos + i);
enc_buffer[i] = reinterpret_cast<const uint8_t *>(buffer)[i] ^ static_cast<uint8_t>(_rotl32(key_, p) + p);
}
res = MemoryStream::Write(enc_buffer, size);
delete [] enc_buffer;
} else {
res = MemoryStream::Write(buffer, size);
}
return res;
}
/**
* ModuleStream
*/
ModuleStream::ModuleStream()
: AbstractStream(), pos_(0), size_(0), base_address_(0), process_(0)
{
}
ModuleStream::~ModuleStream()
{
Close();
}
bool ModuleStream::Open(uint32_t process_id, HMODULE module)
{
Close();
process_ = os::ProcessOpen(process_id);
if (!process_)
return false;
MODULE_INFO module_info;
if (!os::GetModuleInformation(process_, module, &module_info, sizeof(module_info)))
return false;
base_address_ = module_info.address;
size_ = module_info.size;
return true;
}
void ModuleStream::Close()
{
pos_ = 0;
size_ = 0;
base_address_ = NULL;
if (process_) {
os::ProcessClose(process_);
process_ = 0;
}
}
size_t ModuleStream::Read(void *buffer, size_t size)
{
size_t res = os::ProcessRead(process_, reinterpret_cast<uint8_t*>(base_address_) + pos_, buffer, size);
if (res != (size_t)-1)
pos_ += res;
return res;
}
size_t ModuleStream::Write(const void *buffer, size_t size)
{
size_t res = os::ProcessWrite(process_, reinterpret_cast<uint8_t*>(base_address_) + pos_, buffer, size);
if (res != (size_t)-1)
pos_ += res;
return res;
}
uint64_t ModuleStream::Seek(int64_t offset, SeekOrigin origin)
{
intptr_t req_pos;
req_pos = static_cast<intptr_t>(offset);
switch (origin) {
case soBeginning:
break;
case soCurrent:
req_pos += pos_;
break;
case soEnd:
req_pos += size_;
break;
default:
return -1;
}
pos_ = req_pos;
return pos_;
}
/**
* FileStream
*/
FileStream::FileStream(size_t CACHE_ALLOC_SIZE /*= 0x10000*/)
: h_(INVALID_HANDLE_VALUE), cache_mode_(cmNone), CACHE_ALLOC_SIZE_(CACHE_ALLOC_SIZE), cache_pos_(0), cache_size_(0), cache_offset_(0)
{
}
FileStream::~FileStream()
{
Close();
}
bool FileStream::Open(const char *filename, int mode)
{
Close();
h_ = os::FileCreate(filename, mode);
return (h_ != INVALID_HANDLE_VALUE);
}
void FileStream::Close()
{
FlushCache();
if (h_ != INVALID_HANDLE_VALUE) {
os::FileClose(h_);
h_ = INVALID_HANDLE_VALUE;
}
}
uint8_t * FileStream::Cache()
{
uint8_t *ret = cache_.get();
if (ret == NULL)
{
ret = new uint8_t[CACHE_ALLOC_SIZE_];
cache_.reset(ret);
}
return ret;
}
void FileStream::FlushCache(bool need_seek)
{
switch (cache_mode_) {
case cmRead:
if (need_seek && os::FileSeek(h_, cache_offset_ + cache_pos_, soBeginning) == (uint64_t)-1)
throw std::runtime_error("Runtime Error at Flush");
break;
case cmWrite:
if (cache_pos_ && os::FileWrite(h_, Cache(), cache_pos_) != cache_pos_)
throw std::runtime_error("Runtime Error at Flush");
break;
}
cache_mode_ = cmNone;
cache_size_ = 0;
cache_pos_ = 0;
cache_offset_ = 0;
}
size_t FileStream::Read(void *buffer, size_t size)
{
size_t add_size = 0;
if (cache_mode_ == cmRead) {
size_t cache_size = cache_size_ - cache_pos_;
if (size <= cache_size) {
memcpy(buffer, Cache() + cache_pos_, size);
cache_pos_ += size;
return size;
}
if (cache_size) {
memcpy(buffer, Cache() + cache_pos_, cache_size);
cache_pos_ += cache_size;
size -= cache_size;
add_size = cache_size;
buffer = static_cast<uint8_t*>(buffer) + cache_size;
}
}
FlushCache();
if (size < CACHE_ALLOC_SIZE_) {
cache_offset_ = os::FileSeek(h_, 0, soCurrent);
size_t cache_size = os::FileRead(h_, Cache(), CACHE_ALLOC_SIZE_);
// check error
if (cache_size == (size_t)-1)
return cache_size;
if (size > cache_size)
size = cache_size;
cache_mode_ = cmRead;
cache_size_ = cache_size;
memcpy(buffer, Cache(), size);
cache_pos_ = size;
return size + add_size;
}
size_t res = os::FileRead(h_, buffer, size);
// check error
if (res == (size_t)-1)
return res;
return res + add_size;
}
size_t FileStream::Write(const void *buffer, size_t size)
{
size_t add_size = 0;
if (cache_mode_ == cmWrite) {
size_t cache_size = cache_size_ - cache_pos_;
if (size <= cache_size) {
memcpy(Cache() + cache_pos_, buffer, size);
cache_pos_ += size;
return size;
}
if (cache_size) {
memcpy(Cache() + cache_pos_, buffer, cache_size);
cache_pos_ += cache_size;
size -= cache_size;
add_size = cache_size;
buffer = static_cast<const uint8_t*>(buffer) + cache_size;
}
}
FlushCache(true);
if (size < CACHE_ALLOC_SIZE_) {
cache_offset_ = os::FileSeek(h_, 0, soCurrent);
cache_mode_ = cmWrite;
cache_size_ = CACHE_ALLOC_SIZE_;
memcpy(Cache(), buffer, size);
cache_pos_ = size;
return size + add_size;
}
size_t res = os::FileWrite(h_, buffer, size);
// check error
if (res == (size_t)-1)
return res;
return res + add_size;
}
uint64_t FileStream::Seek(int64_t offset, SeekOrigin origin)
{
if (cache_mode_ != cmNone) {
switch (origin) {
case soBeginning:
{
uint64_t pos = static_cast<uint64_t>(offset);
if (pos == cache_offset_ + cache_pos_)
return cache_offset_ + cache_pos_;
if (cache_mode_ == cmRead && pos >= cache_offset_ && pos <= cache_offset_ + cache_size_) {
cache_pos_ = static_cast<size_t>(pos - cache_offset_);
return cache_offset_ + cache_pos_;
}
}
break;
case soCurrent:
if (cache_mode_ == cmRead) {
if (offset + (int64_t)cache_pos_ >= 0 && offset + cache_pos_ <= cache_size_) {
cache_pos_ = static_cast<size_t>(offset + cache_pos_);
return cache_offset_ + cache_pos_;
}
offset -= cache_size_ - cache_pos_;
}
break;
}
FlushCache();
}
return os::FileSeek(h_, offset, origin);
}
uint64_t FileStream::Resize(uint64_t new_size)
{
uint64_t res = Seek(new_size, soBeginning);
FlushCache(true);
os::FileSetEnd(h_);
return res;
}
bool FileStream::ReadLine(std::string &out_line)
{
bool res = true;
out_line.clear();
for (;;) {
char c;
if (Read(&c, sizeof(c)) == 0) {
res = !out_line.empty();
break;
}
if (c == '\n') {
break;
} else if (c == '\r') {
if (Read(&c, sizeof(c)) && c != '\n')
Seek(-1, soCurrent);
break;
} else {
out_line.push_back(c);
}
}
return res;
}
std::string FileStream::ReadAll()
{
std::string res;
size_t sz = static_cast<size_t>(Size());
if (sz) {
res.resize(sz);
Read(&res[0], sz);
}
return res;
}
/**
* Buffer
*/
Buffer::Buffer(const uint8_t *memory)
: memory_(memory), position_(0)
{
}
uint8_t Buffer::ReadByte()
{
uint8_t res;
ReadBuff(&res, sizeof(res));
return res;
}
uint16_t Buffer::ReadWord()
{
uint16_t res;
ReadBuff(&res, sizeof(res));
return res;
}
uint32_t Buffer::ReadDWord()
{
uint32_t res;
ReadBuff(&res, sizeof(res));
return res;
}
uint64_t Buffer::ReadQWord()
{
uint64_t res;
ReadBuff(&res, sizeof(res));
return res;
}
void Buffer::ReadBuff(void *buff, size_t size)
{
memcpy(buff, &memory_[position_], size);
position_ += size;
}