added ref builds and dependencies

master
_xeroxz 4 years ago
parent 79d43e43db
commit ca4f747cc2

388
.gitignore vendored

@ -0,0 +1,388 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Nuget personal access tokens and Credentials
nuget.config
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
.idea/
*.sln.iml

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "dependencies/vmtracer"]
path = dependencies/vmtracer
url = https://githacks.org/vmp2/vmtracer.git

@ -0,0 +1 @@
Subproject commit 2130f86ea886b5a8b81d368b3b6a6f2412c37194

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,50 @@
๏ปฟ
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30907.101
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "um-tracer", "um-tracer\um-tracer.vcxproj", "{3F97516B-DC38-4C7F-857B-0B2D4E079208}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmptest", "vmptest\vmptest.vcxproj", "{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vmtracer", "..\dependencies\vmtracer\src\vmtracer.vcxproj", "{D257C9F6-C705-49D5-84ED-64C9C513C419}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3F97516B-DC38-4C7F-857B-0B2D4E079208}.Debug|x64.ActiveCfg = Release|x64
{3F97516B-DC38-4C7F-857B-0B2D4E079208}.Debug|x64.Build.0 = Release|x64
{3F97516B-DC38-4C7F-857B-0B2D4E079208}.Debug|x86.ActiveCfg = Release|x64
{3F97516B-DC38-4C7F-857B-0B2D4E079208}.Debug|x86.Build.0 = Release|x64
{3F97516B-DC38-4C7F-857B-0B2D4E079208}.Release|x64.ActiveCfg = Release|x64
{3F97516B-DC38-4C7F-857B-0B2D4E079208}.Release|x64.Build.0 = Release|x64
{3F97516B-DC38-4C7F-857B-0B2D4E079208}.Release|x86.ActiveCfg = Release|x64
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Debug|x64.ActiveCfg = Debug|x64
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Debug|x64.Build.0 = Debug|x64
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Debug|x86.ActiveCfg = Debug|Win32
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Debug|x86.Build.0 = Debug|Win32
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Release|x64.ActiveCfg = Release|x64
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Release|x64.Build.0 = Release|x64
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Release|x86.ActiveCfg = Release|Win32
{F98AAFDC-AA2D-4AC2-924A-9BC9895E34D5}.Release|x86.Build.0 = Release|Win32
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Debug|x64.ActiveCfg = Debug|x64
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Debug|x64.Build.0 = Debug|x64
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Debug|x86.ActiveCfg = Debug|Win32
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Debug|x86.Build.0 = Debug|Win32
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Release|x64.ActiveCfg = Release|x64
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Release|x64.Build.0 = Release|x64
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Release|x86.ActiveCfg = Release|Win32
{D257C9F6-C705-49D5-84ED-64C9C513C419}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F16CF1A9-60DA-46EF-9812-FCFA1882FB87}
EndGlobalSection
EndGlobal

@ -0,0 +1,580 @@
/**
* License: Apache 2.0 with LLVM Exception or GPL v3
*
* Author: Jesse Laning
*/
#ifndef ARGPARSE_H
#define ARGPARSE_H
#include <algorithm>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <locale>
#include <map>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
namespace argparse {
namespace detail {
static inline bool _not_space(int ch) { return !std::isspace(ch); }
static inline void _ltrim(std::string& s, bool (*f)(int) = _not_space) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
}
static inline void _rtrim(std::string& s, bool (*f)(int) = _not_space) {
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
}
static inline void _trim(std::string& s, bool (*f)(int) = _not_space) {
_ltrim(s, f);
_rtrim(s, f);
}
static inline std::string _ltrim_copy(std::string s,
bool (*f)(int) = _not_space) {
_ltrim(s, f);
return s;
}
static inline std::string _rtrim_copy(std::string s,
bool (*f)(int) = _not_space) {
_rtrim(s, f);
return s;
}
static inline std::string _trim_copy(std::string s,
bool (*f)(int) = _not_space) {
_trim(s, f);
return s;
}
template <typename InputIt>
static inline std::string _join(InputIt begin, InputIt end,
const std::string& separator = " ") {
std::ostringstream ss;
if (begin != end) {
ss << *begin++;
}
while (begin != end) {
ss << separator;
ss << *begin++;
}
return ss.str();
}
static inline bool _is_number(const std::string& arg) {
std::istringstream iss(arg);
float f;
iss >> std::noskipws >> f;
return iss.eof() && !iss.fail();
}
static inline int _find_equal(const std::string& s) {
for (size_t i = 0; i < s.length(); ++i) {
// if find graph symbol before equal, end search
// i.e. don't accept --asd)f=0 arguments
// but allow --asd_f and --asd-f arguments
if (std::ispunct(static_cast<int>(s[i]))) {
if (s[i] == '=') {
return static_cast<int>(i);
}
else if (s[i] == '_' || s[i] == '-') {
continue;
}
return -1;
}
}
return -1;
}
static inline size_t _find_name_end(const std::string& s) {
size_t i;
for (i = 0; i < s.length(); ++i) {
if (std::ispunct(static_cast<int>(s[i]))) {
break;
}
}
return i;
}
namespace is_vector_impl {
template <typename T>
struct is_vector : std::false_type {};
template <typename... Args>
struct is_vector<std::vector<Args...>> : std::true_type {};
} // namespace is_vector_impl
// type trait to utilize the implementation type traits as well as decay the
// type
template <typename T>
struct is_vector {
static constexpr bool const value =
is_vector_impl::is_vector<typename std::decay<T>::type>::value;
};
} // namespace detail
class argument_parser_t {
private:
public:
class Argument;
class Result {
public:
Result() {}
Result(std::string err) noexcept : _error(true), _what(err) {}
operator bool() const { return _error; }
friend std::ostream& operator<<(std::ostream& os, const Result& dt);
const std::string& what() const { return _what; }
private:
bool _error{ false };
std::string _what{};
};
class Argument {
public:
enum Position : int { LAST = -1, DONT_CARE = -2 };
enum Count : int { ANY = -1 };
Argument& name(const std::string& name) {
_names.push_back(name);
return *this;
}
Argument& names(std::vector<std::string> names) {
_names.insert(_names.end(), names.begin(), names.end());
return *this;
}
Argument& description(const std::string& description) {
_desc = description;
return *this;
}
Argument& required(bool req) {
_required = req;
return *this;
}
Argument& position(int position) {
if (position != Position::LAST) {
// position + 1 because technically argument zero is the name of the
// executable
_position = position + 1;
}
else {
_position = position;
}
return *this;
}
Argument& count(int count) {
_count = count;
return *this;
}
bool found() const { return _found; }
template <typename T>
typename std::enable_if<detail::is_vector<T>::value, T>::type get() {
T t = T();
typename T::value_type vt;
for (auto& s : _values) {
std::istringstream in(s);
in >> vt;
t.push_back(vt);
}
return t;
}
template <typename T>
typename std::enable_if<!detail::is_vector<T>::value, T>::type get() {
std::istringstream in(get<std::string>());
T t = T();
in >> t >> std::ws;
return t;
}
private:
Argument(const std::string& name, const std::string& desc,
bool required = false)
: _desc(desc), _required(required) {
_names.push_back(name);
}
Argument() {}
friend class argument_parser_t;
int _position{ Position::DONT_CARE };
int _count{ Count::ANY };
std::vector<std::string> _names{};
std::string _desc{};
bool _found{ false };
bool _required{ false };
int _index{ -1 };
std::vector<std::string> _values{};
};
argument_parser_t(std::string bin, std::string desc)
: _bin(bin), _desc(desc) {}
Argument& add_argument() {
_arguments.push_back({});
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
Argument& add_argument(const std::string& name, const std::string& long_name,
const std::string& desc, const bool required = false) {
_arguments.push_back(Argument(name, desc, required));
_arguments.back()._names.push_back(long_name);
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
Argument& add_argument(const std::string& name, const std::string& desc,
const bool required = false) {
_arguments.push_back(Argument(name, desc, required));
_arguments.back()._index = static_cast<int>(_arguments.size()) - 1;
return _arguments.back();
}
void print_help(size_t count = 0, size_t page = 0) {
if (page * count > _arguments.size()) {
return;
}
if (page == 0) {
std::cout << "Usage: " << _bin;
if (_positional_arguments.empty()) {
std::cout << " [options...]" << std::endl;
}
else {
int current = 1;
for (auto& v : _positional_arguments) {
if (v.first != Argument::Position::LAST) {
for (; current < v.first; current++) {
std::cout << " [" << current << "]";
}
std::cout
<< " ["
<< detail::_ltrim_copy(
_arguments[static_cast<size_t>(v.second)]._names[0],
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
}
auto it = _positional_arguments.find(Argument::Position::LAST);
if (it == _positional_arguments.end()) {
std::cout << " [options...]";
}
else {
std::cout
<< " [options...] ["
<< detail::_ltrim_copy(
_arguments[static_cast<size_t>(it->second)]._names[0],
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
std::cout << std::endl;
}
std::cout << "Options:" << std::endl;
}
if (count == 0) {
page = 0;
count = _arguments.size();
}
for (size_t i = page * count;
i < std::min<size_t>(page * count + count, _arguments.size()); i++) {
Argument& a = _arguments[i];
std::string name = a._names[0];
for (size_t n = 1; n < a._names.size(); ++n) {
name.append(", " + a._names[n]);
}
std::cout << " " << std::setw(23) << std::left << name << std::setw(23)
<< a._desc;
if (a._required) {
std::cout << " (Required)";
}
std::cout << std::endl;
}
}
Result parse(int argc, const char* argv[]) {
Result err;
if (argc > 1) {
// build name map
for (auto& a : _arguments) {
for (auto& n : a._names) {
std::string name = detail::_ltrim_copy(
n, [](int c) -> bool { return c != static_cast<int>('-'); });
if (_name_map.find(name) != _name_map.end()) {
return Result("Duplicate of argument name: " + n);
}
_name_map[name] = a._index;
}
if (a._position >= 0 || a._position == Argument::Position::LAST) {
_positional_arguments[a._position] = a._index;
}
}
if (err) {
return err;
}
// parse
std::string current_arg;
size_t arg_len;
for (int argv_index = 1; argv_index < argc; ++argv_index) {
current_arg = std::string(argv[argv_index]);
arg_len = current_arg.length();
if (arg_len == 0) {
continue;
}
if (_help_enabled && (current_arg == "-h" || current_arg == "--help")) {
_arguments[static_cast<size_t>(_name_map["help"])]._found = true;
}
else if (argv_index == argc - 1 &&
_positional_arguments.find(Argument::Position::LAST) !=
_positional_arguments.end()) {
err = _end_argument();
Result b = err;
err = _add_value(current_arg, Argument::Position::LAST);
if (b) {
return b;
}
if (err) {
return err;
}
}
else if (arg_len >= 2 &&
!detail::_is_number(current_arg)) { // ignores the case if
// the arg is just a -
// look for -a (short) or --arg (long) args
if (current_arg[0] == '-') {
err = _end_argument();
if (err) {
return err;
}
// look for --arg (long) args
if (current_arg[1] == '-') {
err = _begin_argument(current_arg.substr(2), true, argv_index);
if (err) {
return err;
}
}
else { // short args
err = _begin_argument(current_arg.substr(1), false, argv_index);
if (err) {
return err;
}
}
}
else { // argument value
err = _add_value(current_arg, argv_index);
if (err) {
return err;
}
}
}
else { // argument value
err = _add_value(current_arg, argv_index);
if (err) {
return err;
}
}
}
}
if (_help_enabled && exists("help")) {
return Result();
}
err = _end_argument();
if (err) {
return err;
}
for (auto& p : _positional_arguments) {
Argument& a = _arguments[static_cast<size_t>(p.second)];
if (a._values.size() > 0 && a._values[0][0] == '-') {
std::string name = detail::_ltrim_copy(a._values[0], [](int c) -> bool {
return c != static_cast<int>('-');
});
if (_name_map.find(name) != _name_map.end()) {
if (a._position == Argument::Position::LAST) {
return Result(
"Poisitional argument expected at the end, but argument " +
a._values[0] + " found instead");
}
else {
return Result("Poisitional argument expected in position " +
std::to_string(a._position) + ", but argument " +
a._values[0] + " found instead");
}
}
}
}
for (auto& a : _arguments) {
if (a._required && !a._found) {
return Result("Required argument not found: " + a._names[0]);
}
if (a._position >= 0 && argc >= a._position && !a._found) {
return Result("Argument " + a._names[0] + " expected in position " +
std::to_string(a._position));
}
}
return Result();
}
void enable_help() {
add_argument("-h", "--help", "Shows this page", false);
_help_enabled = true;
}
bool exists(const std::string& name) const {
std::string n = detail::_ltrim_copy(
name, [](int c) -> bool { return c != static_cast<int>('-'); });
auto it = _name_map.find(n);
if (it != _name_map.end()) {
return _arguments[static_cast<size_t>(it->second)]._found;
}
return false;
}
template <typename T>
T get(const std::string& name) {
auto t = _name_map.find(name);
if (t != _name_map.end()) {
return _arguments[static_cast<size_t>(t->second)].get<T>();
}
return T();
}
private:
Result _begin_argument(const std::string& arg, bool longarg, int position) {
auto it = _positional_arguments.find(position);
if (it != _positional_arguments.end()) {
Result err = _end_argument();
Argument& a = _arguments[static_cast<size_t>(it->second)];
a._values.push_back((longarg ? "--" : "-") + arg);
a._found = true;
return err;
}
if (_current != -1) {
return Result("Current argument left open");
}
size_t name_end = detail::_find_name_end(arg);
std::string arg_name = arg.substr(0, name_end);
if (longarg) {
int equal_pos = detail::_find_equal(arg);
auto nmf = _name_map.find(arg_name);
if (nmf == _name_map.end()) {
return Result("Unrecognized command line option '" + arg_name + "'");
}
_current = nmf->second;
_arguments[static_cast<size_t>(nmf->second)]._found = true;
if (equal_pos == 0 ||
(equal_pos < 0 &&
arg_name.length() < arg.length())) { // malformed argument
return Result("Malformed argument: " + arg);
}
else if (equal_pos > 0) {
std::string arg_value = arg.substr(name_end + 1);
_add_value(arg_value, position);
}
}
else {
Result r;
if (arg_name.length() == 1) {
return _begin_argument(arg, true, position);
}
else {
for (char& c : arg_name) {
r = _begin_argument(std::string(1, c), true, position);
if (r) {
return r;
}
r = _end_argument();
if (r) {
return r;
}
}
}
}
return Result();
}
Result _add_value(const std::string& value, int location) {
if (_current >= 0) {
Result err;
Argument& a = _arguments[static_cast<size_t>(_current)];
if (a._count >= 0 && static_cast<int>(a._values.size()) >= a._count) {
err = _end_argument();
if (err) {
return err;
}
goto unnamed;
}
a._values.push_back(value);
if (a._count >= 0 && static_cast<int>(a._values.size()) >= a._count) {
err = _end_argument();
if (err) {
return err;
}
}
return Result();
}
else {
unnamed:
auto it = _positional_arguments.find(location);
if (it != _positional_arguments.end()) {
Argument& a = _arguments[static_cast<size_t>(it->second)];
a._values.push_back(value);
a._found = true;
}
// TODO
return Result();
}
}
Result _end_argument() {
if (_current >= 0) {
Argument& a = _arguments[static_cast<size_t>(_current)];
_current = -1;
if (static_cast<int>(a._values.size()) < a._count) {
return Result("Too few arguments given for " + a._names[0]);
}
if (a._count >= 0) {
if (static_cast<int>(a._values.size()) > a._count) {
return Result("Too many arguments given for " + a._names[0]);
}
}
}
return Result();
}
bool _help_enabled{ false };
int _current{ -1 };
std::string _bin{};
std::string _desc{};
std::vector<Argument> _arguments{};
std::map<int, int> _positional_arguments{};
std::map<std::string, int> _name_map{};
};
std::ostream& operator<<(std::ostream& os, const argument_parser_t::Result& r) {
os << r.what();
return os;
}
template <>
inline std::string argument_parser_t::Argument::get<std::string>() {
return detail::_join(_values.begin(), _values.end());
}
template <>
inline std::vector<std::string>
argument_parser_t::Argument::get<std::vector<std::string>>() {
return _values;
}
} // namespace argparse
#endif

@ -0,0 +1,36 @@
.data
__mbase dq 0h
public __mbase
.code
__lconstbzx proc
mov al, [rsi]
lea rsi, [rsi+1]
xor al, bl
dec al
ror al, 1
neg al
xor bl, al
pushfq ; save flags...
cmp ax, 01Ch
je swap_val
; the constant is not 0x1C
popfq ; restore flags...
sub rbp, 2
mov [rbp], ax
mov rax, __mbase
add rax, 059FEh ; calc jmp rva is 0x59FE...
jmp rax
swap_val: ; the constant is 0x1C
popfq ; restore flags...
mov ax, 5 ; bit 5 is VMX in ECX after CPUID...
sub rbp, 2
mov [rbp], ax
mov rax, __mbase
add rax, 059FEh ; calc jmp rva is 0x59FE...
jmp rax
__lconstbzx endp
end

@ -0,0 +1,210 @@
#include <iostream>
#include <Windows.h>
#include <fstream>
#include <filesystem>
#include "vmtracer.hpp"
#include "vmp2.hpp"
#include "cli-parser.hpp"
extern "C" void __lconstbzx(void);
extern "C" u64 __mbase;
#define NT_HEADER(x) \
reinterpret_cast<PIMAGE_NT_HEADERS64>( \
reinterpret_cast<PIMAGE_DOS_HEADER>(x)->e_lfanew + x)
inline std::vector<vmp2::entry_t> traces;
inline vmp2::file_header trace_header;
int __cdecl main(int argc, const char** argv)
{
argparse::argument_parser_t parser(
"um-tracer", "usermode virtual instruction tracer");
parser.add_argument()
.names({ "--bin", "--vmpbin" })
.description("path to a binary protected with VMProtect 2")
.required(true);
parser.add_argument()
.names({ "--table", "--vmtable" })
.description("relative virtual address to the vm handler table")
.required(true);
parser.add_argument()
.names({ "--base", "--imagebase" })
.description("image base from OptionalHeader::ImageBase")
.required(true);
parser.add_argument()
.names({ "--out", "--output" })
.description("name and/or path to output file")
.required(true);
parser.enable_help();
auto err = parser.parse(argc, argv);
if (err)
{
std::cout << err << std::endl;
return -1;
}
if (parser.exists("help"))
{
parser.print_help();
return 0;
}
/*
the vm_handlers are encrypted/encoded with a basic
math operation... typically a NOT, XOR, NEG, etc...
You can determine what type of encryption your binary
is using by first finding where the LEA r12, vm_handlers
is located, then follow the usage of r12 until you see
MOV GP, [r12 + rax * 8], then follow the usage of the GP...
For example:
.vmp1:00000001401D1015 lea r12, vm_handlers
.vmp1:00000001401D0C0A mov rdx, [r12+rax*8]
.vmp1:00000001401D0C10 ror rdx, 25h
Note:
R12 and RAX always seem to be used for this vm handler index...
You could signature scan for LEA r12, ? ? ? ? and find the vm handler
table really easily by manually inspecting each result...
*/
vm::decrypt_handler_t _decrypt_handler =
[](u64 val) -> u64
{
return val ^ 0x7F3D2149;
};
vm::encrypt_handler_t _encrypt_handler =
[](u64 val) -> u64
{
return val ^ 0x7F3D2149;
};
vm::handler::edit_entry_t _edit_entry =
[](u64* entry_ptr, u64 val) -> void
{
DWORD old_prot;
VirtualProtect(entry_ptr, sizeof val,
PAGE_EXECUTE_READWRITE, &old_prot);
*entry_ptr = val;
VirtualProtect(entry_ptr, sizeof val,
old_prot, &old_prot);
};
const auto module_base =
reinterpret_cast<std::uintptr_t>(
LoadLibraryExA(parser.get<std::string>("bin").c_str(),
NULL, DONT_RESOLVE_DLL_REFERENCES));
// used in LCONSTBZX hook...
__mbase = module_base;
const auto handler_table_rva = std::strtoul(
parser.get<std::string>("table").c_str(), nullptr, 16);
const auto image_base = std::strtoull(
parser.get<std::string>("base").c_str(), nullptr, 16);
const auto handler_table_ptr =
reinterpret_cast<std::uintptr_t*>(
module_base + handler_table_rva);
/*
the VM handler table is an array of 256 QWORD's... each encrypted differently per-binary...
each one of these is an encrypted RVA to a virtual instruction...
.vmp1:00000001401D25D3 vm_handlers dq 3A28FA000000028h, 3A40E4000000028h, 3A2F5C000000028h
.vmp1:00000001401D25D3 dq 3A1096000000028h, 3A3DBC000000028h, 3A1DDA000000028h
.vmp1:00000001401D25D3 dq 3A6032000000028h, 2 dup(3A40E4000000028h), 3A2B5A000000028h
.vmp1:00000001401D25D3 dq 3A4004000000028h, 3A2810000000028h, 3A446A000000028h
.vmp1:00000001401D25D3 dq 3A39B6000000028h, 3A6728000000028h, 3A6032000000028h
.vmp1:00000001401D25D3 dq 3A34F0000000028h, 3A46F2000000028h, 3A0170000000028h
.vmp1:00000001401D25D3 dq 3A0952000000028h, 3A4004000000028h, 3A494E000000028h
.vmp1:00000001401D25D3 dq 3A35C2000000028h, 3A4A1E000000028h, 3A37D8000000028h
.vmp1:00000001401D25D3 dq 3A1482000000028h, 3A6492000000028h, 3A2948000000028h
.vmp1:00000001401D25D3 dq 3A2D1C000000028h, 2 dup(3A6ABE000000028h), 3A068A000000028h
.vmp1:00000001401D25D3 dq 3A3F52000000028h, 3A118E000000028h, 3A27BE000000028h
// .... many more ...
*/
vm::handler::table_t handler_table(handler_table_ptr, _edit_entry);
// set all vm handler callbacks to just
// print the rolling decrypt key and handler idx...
for (auto idx = 0u; idx < 256; ++idx)
{
handler_table.set_callback(idx,
[](vm::registers* regs, u8 handler_idx) -> void
{
vmp2::entry_t entry;
entry.decrypt_key = regs->rbx;
entry.handler_idx = handler_idx;
entry.vip = regs->rsi;
memcpy(&entry.regs, &regs->r15, sizeof entry.regs);
memcpy(&entry.vregs, (void*)regs->rdi, sizeof entry.vregs);
for (auto idx = 0u; idx < sizeof(entry.vsp) / 8; ++idx)
entry.vsp.qword[idx] = reinterpret_cast<u64*>(regs->rbp)[idx];
traces.push_back(entry);
std::printf("> TID = %d, handler idx = %d, decryption key = 0x%p\n",
GetCurrentThreadId(), handler_idx, regs->rbx);
}
);
}
vm::tracer_t tracer(
module_base,
image_base,
_decrypt_handler,
_encrypt_handler,
&handler_table
);
// change vm handler 0x55 (LCONSTBZX) to our implimentation of it...
auto _meta_data = handler_table.get_meta_data(0x55);
_meta_data.virt = reinterpret_cast<u64>(&__lconstbzx);
handler_table.set_meta_data(0x55, _meta_data);
std::ofstream vmp2_file(parser.get<std::string>("out"), std::ios::binary);
memcpy(&trace_header.magic, "VMP2", sizeof "VMP2" - 1);
trace_header.epoch_time = time(nullptr);
trace_header.entry_offset = sizeof trace_header;
trace_header.advancement = vmp2::exec_type_t::forward;
trace_header.version = vmp2::version_t::v1;
trace_header.module_base = module_base;
// patch vm handler table...
tracer.start();
// call entry point...
auto result = reinterpret_cast<int (*)()>(
NT_HEADER(module_base)->OptionalHeader.AddressOfEntryPoint + module_base)();
std::printf("result = %d\n", result);
// unpatch vm handler table...
tracer.stop();
// write vmp2 file to disk...
trace_header.entry_count = traces.size();
vmp2_file.write((char*)&trace_header, sizeof trace_header);
for (auto& trace : traces)
vmp2_file.write((char*)&trace, sizeof trace);
vmp2_file.close();
std::printf("> finished vm trace...\n");
std::getchar();
}

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{3f97516b-dc38-4c7f-857b-0b2d4e079208}</ProjectGuid>
<RootNamespace>vmtracer</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>um-tracer</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(ProjectDir)..\libs\*;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="cli-parser.hpp" />
<ClInclude Include="vmp2.hpp" />
<ClInclude Include="vmtracer.hpp" />
</ItemGroup>
<ItemGroup>
<MASM Include="lconstbzx.asm" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\vmptest\vmptest.vcxproj">
<Project>{f98aafdc-aa2d-4ac2-924a-9bc9895e34d5}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

@ -0,0 +1,34 @@
๏ปฟ<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="vmtracer.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vmp2.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cli-parser.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="lconstbzx.asm">
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
</Project>

@ -0,0 +1,72 @@
#pragma once
#include "vmtracer.hpp"
namespace vmp2
{
enum class exec_type_t
{
forward,
backward
};
enum class version_t
{
invalid,
v1 = 0x101
};
struct file_header
{
u32 magic; // VMP2!
u64 epoch_time;
u64 module_base;
exec_type_t advancement;
version_t version;
u32 entry_count;
u32 entry_offset;
};
struct entry_t
{
u8 handler_idx;
u64 decrypt_key;
u64 vip;
union
{
struct
{
u64 r15;
u64 r14;
u64 r13;
u64 r12;
u64 r11;
u64 r10;
u64 r9;
u64 r8;
u64 rbp;
u64 rdi;
u64 rsi;
u64 rdx;
u64 rcx;
u64 rbx;
u64 rax;
u64 rflags;
};
u64 raw[16];
} regs;
union
{
u64 qword[0x28];
u8 raw[0x140];
} vregs;
union
{
u64 qword[0x20];
u8 raw[0x100];
} vsp;
};
}

@ -0,0 +1,118 @@
#pragma once
#include <cstdint>
#include <xmmintrin.h>
using u8 = unsigned char;
using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;
using u128 = __m128;
extern "C" void __vtrap(void);
namespace vm
{
typedef struct _registers
{
u128 xmm0;
u128 xmm1;
u128 xmm2;
u128 xmm3;
u128 xmm4;
u128 xmm5;
u128 xmm6;
u128 xmm7;
u128 xmm8;
u128 xmm9;
u128 xmm10;
u128 xmm11;
u128 xmm12;