Giter VIP home page Giter VIP logo

perses's Introduction

Introduction

PERSES is a X86 code obfuscation engine that works with Portable Executable files. The obfuscation works by replacing a specific instruction with a larger more sophisticated set that is semantically compatible to the original. PERSES only mutates 4 instructions yet has adverse effects on analyzers/decompilers due to the method of mutation. For more information on PERSES' inner workings, please check out the article written here.

PERSES is a work in progress and does not attempt to be a replacement for any established code obfuscation engine, so please be mindful when using it to protect your code. Furthermore, X64 support can be slightly improved and augmented to ensure semantical accuracy.

Reference Manual

PERSES by default works off a command line. Listed below are the arguments requried to utilize PERSES.

Argument Description May Require
-f or --file Path to the input PE file. ✔️
-a or -address Address or list of addresses required to be mutated. ✔️
-s or --symbol Symbol or list of symbols to be mutated. This requires a linked .map file.
--map Map file to be linked. IDA Pro .map files must have their extension replaced with .ida.
--list List of functions to be mutated. Each entry must envelop one line and be formatted as 0x1000:0x2000 where 0x1000 is the start and 0x2000 is the end of the routine.
--rets Allow PERSES to build a RET gadget pool used to create JMPs to random locations.
--scan Force PERSES to scan for code protection markers.

Both symbols and addresses can be used, but atleast one of them must be present.

ℹ️ Due to limitations in the argparse library, if more than one address or symbol are required, please append the -a or -s argument and parameters last.

Working with PERSES Manually

If desired, PERSES can be used manually to generate mutated binaries. To begin, one must declare a X86BinaryApplication instance with the provided template parameter.

  • X86BinaryApplication<PERSES_64BIT>(filepath) to generate a X86_64 instance.
  • X86BinaryApplication<PERSES_32BIT>(filepath) to generate a X86 instance.

RET Gadgets

After instantiating the object, the RET gadget pool mentioned above can be optionally created with perses::buildKnownRetGadgets(app).

MAP Files

MAP files are optionally produced by compilers to show symbols and sections present in a binary with their corresponding address. PERSES allows MAP files from IDA Pro and MSVC (tested on VS2022) to be linked via X86BinaryApplication::linkMapFile. Afterwards, symbols can be traversed via X86BinaryApplication::getSymbols or added directly into the mutation queue by calling addRoutineBySymbol. For instance, after linking the map file, adding main to the mutation queue is as simple as:

app->addRoutineBySymbol("main", PERSES_MARKER_MUTATION);

MAP files can aid function size calculation by exposing known symbols, however, MAP linking is completely optional and only added as a convenience.

Function Lists

If mutating a batch of functions is wanted, function lists can be parsed in order to add the specified routines automatically. This is done by calling parseFunctionList. Please be mindful of the required format listed above in the argument table. Futhermore, the end address supplied is expected to be the end of a function, providing anything else will likely result in instability of the output program.

Markers

The PersesSDK can be included into a project to emit a scannable pattern into code. PERSES makes use of compiler intrinsics to generate unique patterns. Beginning and end macros named PERSES_MUTATION_START() and PERSES_MUTATION_END() are provided.

Applying Transforms

Applying mutation on all routines in the queue is done by calling X86BinaryApplication::transformRoutines. Transforms are applied via the corresponding schema. At the moment, there is only one schema supplied; MutationLight.

Compiling.

Compilation of the new binary can be done with X86BinaryApplication::compile. PERSES creates a new file and appends .perses after the original filename.

Showcase

Below are some example programs created to show the efficacy in regards to crippling decompiler output.

Hello, world!

int main()
{
	PERSES_MUTATION_START()

	printf("Hello, world!\n");
	Sleep(100);

	PERSES_MUTATION_END()

	return getchar();
}

Output

Output1

Jump Table Mutation

int main()
{
	int input = 0;

	std::cin >> input;

	switch (input)
	{
	case 0:
		std::cout << "Value is zero" << std::endl;
		break;
	case 1:
		std::cout << "Value is one" << std::endl;
		break;
	case 2:
		std::cout << "Value is two" << std::endl;
		break;
	case 3:
		std::cout << "Value is three" << std::endl;
		break;
	case 4:
		std::cout << "Value is four" << std::endl;
		break;
	default:
		std::cerr << "Unhandled value!" << std::endl;
		break;
	}

	return getchar();
}

Full function mutation using command line

perses -f MutationTesting.exe --map MutationTesting.map --rets -s _main

Output

Output2

Modification

Additional schemas can be created then attached to X86BinaryApplication::buildSchema. Alternatively, MutationLight can be extended as it only supports a minimal set of instructions. In order to modify the existing schema, please thoroughly read and understand MutationLight.cpp.

Building (Windows)

PERSES utilizes cmkr. In order to build the PERSES project, please run the following commands:

git clone --recursive https://github.com/mike1k/perses.git
cmake -B build

Dependencies

PERSES makes use of multiple great libraries in order to achieve it's objective.

perses's People

Contributors

gmh5225 avatar lguilhermee avatar mike1k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

perses's Issues

This instruction will cause the program to crash

  • Transforming 0x140002fc2 (0x5f) - [ mov r8b, byte ptr [rbp-0x2C] ]

vvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvv1111

//
printf("vvvvvvvvvvvvvvvvvvv\n");
/**/
switch (insn.decoded.mnemonic)
{
case ZYDIS_MNEMONIC_PUSH:
handled = handlePush(&insn);
break;
case ZYDIS_MNEMONIC_MOV:
printf("vvvvvvvvvvvvvvvvvvv1111\n");
handled = handleMov(&insn);
printf("vvvvvvvvvvvvvvvvvvv2222\n");

Consider adding `cmkr` topic to the repo

Heya,

Would be nice if you could add the cmkr topic to the repository (and maybe a few others like x86, obfuscation, etc for better discoverability). I'm using it to make sure new releases stay compatible and to look for possible ways to improve.

Cheers,

Duncan

The compiled program would crash.

Hi, I have used perses to compile a demo program.
After I started the compiled(obfuscated) program, it just crashed.
Some simple analysis later, I saw the compiled process did not jump over the code snippet of PERSES_MUTATION_START macro.

eg.

image

If I set eip explicitly so that eip pointed to the instruction following cli, then everything went well.

Relocation table: improper initialization

template
class RelocationDirectory : pepp::msc::NonCopyable
{
private:
//! Setup the directory
void _setup(Image* image) {
m_image = image;
m_base = reinterpret_cast<decltype(m_base)>(
&image->base()[image->getPEHdr().rvaToOffset(
image->getPEHdr().getOptionalHdr().getDataDir(DIRECTORY_ENTRY_BASERELOC).VirtualAddress)]); //this line
m_section =
&image->getSectionHdrFromVa(image->getPEHdr().getOptionalHdr().getDataDir(DIRECTORY_ENTRY_BASERELOC).VirtualAddress);
}
}
In the line of m_base = *, rvaToOffset may return zero like empty relocation table.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.