You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.1 KiB
177 lines
4.1 KiB
#include "perses.hpp"
|
|
#include <argparse/argparse.hpp>
|
|
|
|
template<int BitSize>
|
|
void createApplication(perses::X86BinaryApplication<BitSize>* app, argparse::ArgumentParser& args)
|
|
{
|
|
spdlog::stopwatch sw;
|
|
int numSeconds = 0;
|
|
float numMinutes = 0.f;
|
|
|
|
if (args.is_used("--rets"))
|
|
perses::buildKnownRetGadgets(app);
|
|
|
|
if (auto param = args.present<std::string>("--map"))
|
|
{
|
|
std::filesystem::path path = *param;
|
|
|
|
if (!std::filesystem::exists(path))
|
|
{
|
|
logger()->critical("Unable to parse map file, non existent!");
|
|
goto Delete;
|
|
}
|
|
|
|
if (path.extension().string() == ".ida")
|
|
app->linkMapFile(perses::MapFileType::kIDAPro, *param);
|
|
else
|
|
app->linkMapFile(perses::MapFileType::kMSVC, *param);
|
|
}
|
|
|
|
if (auto param = args.present<std::string>("--list"))
|
|
{
|
|
std::filesystem::path path = *param;
|
|
|
|
if (!std::filesystem::exists(path))
|
|
{
|
|
logger()->critical("Unable to parse list file, non existent!");
|
|
goto Delete;
|
|
}
|
|
|
|
app->parseFunctionList(*param);
|
|
}
|
|
|
|
if (auto param = args.present<std::vector<std::string>>("-a"))
|
|
{
|
|
for (auto& uaddr : *param)
|
|
{
|
|
perses::u64 addr = strtoull(uaddr.c_str(), nullptr, 16);
|
|
if (addr > 0)
|
|
app->addRoutineByAddress(addr, PERSES_MARKER_MUTATION);
|
|
}
|
|
}
|
|
|
|
if (auto param = args.present<std::vector<std::string>>("-s"))
|
|
{
|
|
if (app->hasMapFile())
|
|
{
|
|
for (auto& sym : *param)
|
|
{
|
|
app->addRoutineBySymbol(sym, PERSES_MARKER_MUTATION);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger()->critical("Unable to use symbols argument without a linked .MAP file!");
|
|
goto Delete;
|
|
}
|
|
}
|
|
|
|
if (args.is_used("--scan"))
|
|
app->scanForMarkers();
|
|
|
|
if (app->getRoutines().empty())
|
|
{
|
|
logger()->critical("Unable to mutate: no routines in queue.");
|
|
goto Delete;
|
|
}
|
|
|
|
app->transformRoutines();
|
|
app->compile();
|
|
|
|
logger()->info("Mutated {} routines.", app->getRoutines().size());
|
|
|
|
numSeconds = std::chrono::duration_cast<std::chrono::seconds>(sw.elapsed()).count();
|
|
numMinutes = (float)numSeconds / 60.f;
|
|
|
|
if (numSeconds > 60)
|
|
logger()->info("It took {} minutes and {} seconds to complete this operation.", (int)(numSeconds / 60), (int)((float)(numMinutes - (int)numMinutes) * 60.f));
|
|
else
|
|
logger()->info("It took {} seconds to complete this operation.", numSeconds);
|
|
|
|
Delete:
|
|
delete app;
|
|
}
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
argparse::ArgumentParser args("PERSES");
|
|
void* app = nullptr;
|
|
|
|
args.add_argument("-f", "--file")
|
|
.help("Input file path.")
|
|
.required();
|
|
args.add_argument("-x64")
|
|
.help("Required for X64 PE files.")
|
|
.default_value(false)
|
|
.implicit_value(true);
|
|
args.add_argument("-a", "--address")
|
|
.help("Address(es) to mutate")
|
|
.remaining();
|
|
args.add_argument("-s", "--symbol")
|
|
.help("Symbol(s) to mutate (requires .MAP)")
|
|
.remaining();
|
|
args.add_argument("--list")
|
|
.help("Parsable function list (NOTE: all entries in the list will be added).");
|
|
args.add_argument("--map")
|
|
.help("Parsable map file (NOTE: IDA Pro .MAP files must have their extension named as \".ida\").");
|
|
args.add_argument("--rets")
|
|
.help("Use RET gadgets.")
|
|
.default_value(false)
|
|
.implicit_value(true);
|
|
args.add_argument("--scan")
|
|
.help("Scan for protection markers.")
|
|
.default_value(false)
|
|
.implicit_value(true);
|
|
|
|
if (argc <= 1)
|
|
{
|
|
args.print_help();
|
|
return 1;
|
|
}
|
|
|
|
try {
|
|
args.parse_args(argc, argv);
|
|
}
|
|
catch (const std::runtime_error& err) {
|
|
args.print_help();
|
|
return 1;
|
|
}
|
|
|
|
logger()->debug("PERSES Code Protection Engine");
|
|
|
|
std::string filepath = args.get<std::string>("-f");
|
|
|
|
if (!std::filesystem::exists(filepath))
|
|
{
|
|
logger()->critical("Unable to find file: {}.", filepath);
|
|
return 0;
|
|
}
|
|
|
|
if (args.get<bool>("-x64"))
|
|
{
|
|
createApplication(new perses::X86BinaryApplication<PERSES_64BIT>(filepath), args);
|
|
}
|
|
else
|
|
{
|
|
createApplication(new perses::X86BinaryApplication<PERSES_32BIT>(filepath), args);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
std::shared_ptr<spdlog::logger> logger()
|
|
{
|
|
static std::shared_ptr<spdlog::logger> log = nullptr;
|
|
|
|
if (!log)
|
|
{
|
|
log = spdlog::stdout_color_mt("console");
|
|
log->set_level(spdlog::level::debug);
|
|
log->set_pattern("[%^PERSES%$] %v");
|
|
|
|
spdlog::set_error_handler([](const std::string& msg) { printf("*** LOG ERROR: %s ***\n", msg.c_str()); });
|
|
}
|
|
|
|
return log;
|
|
} |