Hold variables in memory encrypted

Hi. I am getting started reading Python 3.10.7 sources, having had a bad experience with module/class/package naming conventions and relative imports with init.py. I felt like I could patch the language into allowing certain things, that it usually wouldn’t. {Not yet braces} {My first language was Perl5}

Kept thinking, and eventually tested Transpilers (Python to Rust, C), the Python3 Compiler Nuitka, and @njit Numba.

Finally arrived at a train of thought derived from this: 18849-hyperion-implementation-of-a-pe-crypter.pdf (exploit-db.com)

I realize Python isn’t ideal for certain applications, as in Malware Research, since even getting a cross-platform monolithic standalone binary, isn’t quite easy, but how about introducing a crypto loader for Python projects (the Nuitka C wrapper could be useful) or coming from Numba, build a @crypt decorator that holds all memory of a function (at least data - variables, objects, dict’s, …) in AES encrypted memory. Until accessed. I am not quite sure about the state-of-the-art of polymorphic encryption.

This would be meaningful for global variables and non-internal data structures as well.

Any thoughts?

Best,
zdanl

The AES key will in memory to allow the decrypt,
so it’s just security by obscurity isn’t it?
How is that useful?

2 Likes

Isn’t there a huge performance problem - you make a tiny change to a variable (increase a reference count for example) and you have to modify your entire memory because the encrypted version is completely different? (And if the encrypted version isn’t completely different, that’s probably an easy way of making small, known changes to break the encryption)

1 Like

Hi. Great comment. The paper about the Runtime Decryption I referenced, states that a few bits of the AES key are being brute-forced by the container at runtime. Self brute-forcing in very few milliseconds. So, in fact, the key is not present in memory. It is also not, not present in memory.

The container has to bruteforce the encryption key which would consume a large amount of time if the complete key space is
used. Therefore, the key space is reduced and the key is generated using the following
algorithm:
Listing 1: AES Key Generation Algorithm
1 unsigned char key [ AES KEY SIZE ] ;
2 fo r ( i n t i =0; i <AES KEY SIZE ; i ++){
3 i f ( i <KEY SIZE ) key [ i ] = rand ( ) % KEY RANGE;
4 else key [ i ] = 0;
5 }
The listing uses two important constants (which are defined in the crypters source
code): KEY SIZE and KEY RANGE. KEY RANGE specifies the the key size and can
have a value between 0 and 15 (unused bytes are filled with zeros). The maximum
value of each key element is specified in KEY SIZE and can be a value between 0 and
255

This still doesn’t seem to have a purpose - if the Python interpreter can brute-force the key fast enough to not have a slowdown, then an attacker could too, defeating the point of this memory protection.

2 Likes