Jump to content
Tuts 4 You

Python Pyarmor + My Protector


0x72
Go to solution Solved by Extreme Coders,

Recommended Posts

Language : Python
Platform : Windows
OS Version : All 
Packer / Protector : Pyarmor  + My Protector

Description :

Want to see if someone can unpack it, want to use this obfuscator for my future aplications in python

Screenshot : 

Spoiler

 xgiEYc.png

Download : 

Virustotal: https://www.virustotal.com/gui/file/fec987a11c8bdd47355529389d75f1f2cb0f980a763efa21e796dd1a21619989/detection
Download: https://anonfile.com/3fn5o8gdo5/UnpackME_by_0x72_rar

UnpackME by 0x72.rar

Edited by Teddy Rogers
Please use correct formatting and attach your file to the topic (do not use external file host)
  • Like 1
Link to comment
Share on other sites

CodeExplorer

The program is a 64 bit executable! (Portable Executable 64)
Did you code this UnpackMe yourself?
 

Link to comment
Share on other sites

10 minutes ago, CodeExplorer said:

The program is a 64 bit executable! (Portable Executable 64)
Did you code this UnpackMe yourself?
 

Half of obfuscation is made manually and for the rest i used pyarmor

To make it Executable i used pyinstaller 

Edited by 0x72
Link to comment
Share on other sites

  • 4 weeks later...
  • Solution
Extreme Coders

Not necessary to unpack to get the key.

Key:

Spoiler

image.png.2846c516e23d847e927c7c7fd1ad3dd6.png

GENERATE-KEY-0X72GOD-UNPACKME

Converted it to run on Linux because it's easier to compile CPython on Linux and also because I don't have Visual Studio installed in the Windows VM.
This also explains why "title" and "cls" commands were not found.

Steps :

Spoiler

 

1. Use pyinstxtractor.py to extract the executable in Python 3.7

2. Using the extracted files, create the following directory structure


.
|-- martisor.pyc
`-- pytransform
    |-- __init__.py
    |-- _pytransform.dll
    |-- license.lic
    `-- pytransform.key

1 directory, 5 files

For running on Linux, you need _pytransform.so downloadable from https://pyarmor.dashingsoft.com/platforms.html

3. Install psutil using pip (Required for pyarmor). From now on, you can just run python3.7 martisor.pyc instead of the unpackme executable.

4. pyarmor encrypts the code objects on disk and they are only decrypted at runtime just before they are executed. The entire logic is implemented in _pytransform.dll. There are anti-debugging/timing checks to prevent us from using a debugger to dump code objects from memory. But there's no need to use a debugger at all when CPython itself is open source. :)

5. Compile Python 3.7 from source. Modify the _PyEval_EvalFrameDefault function such that it dumps the code object to disk. By doing so we do not need to bother about all the anti-debugging and encrypted stuff. This is because pyarmor decrypts the code object in memory before it hands it to the Python VM for execution.

6. Run strings on the dumped code  object. We get many base64 strings. Like this one: CkdFTkVSQVRFLUtFWS0wWDcyR09ELVVOUEFDS01FCg==

7. Base64 decode and profit!

 

 

  • Like 11
Link to comment
Share on other sites

  • 3 weeks later...

5. Compile Python 3.7 from source. Modify the _PyEval_EvalFrameDefault function such that it dumps the code object to disk. By doing so we do not need to bother about all the anti-debugging and encrypted stuff. This is because pyarmor decrypts the code object in memory before it hands it to the Python VM for execution.

 

I don't understand this step at all

Edited by 0x72
Link to comment
Share on other sites

  • 5 weeks later...
On 3/29/2020 at 9:50 PM, Extreme Coders said:

5. Compile Python 3.7 from source. Modify the _PyEval_EvalFrameDefault function such that it dumps the code object to disk. By doing so we do not need to bother about all the anti-debugging and encrypted stuff. This is because pyarmor decrypts the code object in memory before it hands it to the Python VM for execution.

Hi Extreme, im trying to do this, but the code is unredable after dumped!

How you do it?

Which function you have used?

 

Thanks in advance :)

 

Link to comment
Share on other sites

Extreme Coders
3 hours ago, Powante said:

Hi Extreme, im trying to do this, but the code is unredable after dumped!

The code will be unreadable as it's encrypted. But at least for this challenge that is not an issue. You can simply run strings on the dumped file.

Link to comment
Share on other sites

I need to do the same, research for a string, but with "unredable" i means that the dumped code it is not binary.

I think i did not write the function for dumping correctly, do you have a sample or the function you have write for dumping?

 

Thank you very much! 

Edited by Powante
Link to comment
Share on other sites

  • 3 weeks later...

Thanks to "Extreme Coders", I've never programmed in python before, but after reading all your public material and following the recommended steps in this thread I've been able to desofuscate the code.
If they tell you how to do it you will understand it, but if they guide you and you have to discover how to do it you will learn

martisor_unpacked.py

  • Like 4
Link to comment
Share on other sites

  • 3 weeks later...
shadow.Walker
On 3/29/2020 at 10:50 PM, Extreme Coders said:

5. Compile Python 3.7 from source. Modify the _PyEval_EvalFrameDefault function such that it dumps the code object to disk. By doing so we do not need to bother about all the anti-debugging and encrypted stuff. This is because pyarmor decrypts the code object in memory before it hands it to the Python VM for execution.

Quote

Modify the _PyEval_EvalFrameDefault function such that it dumps the code object to disk

do u mind explaining how to do that? how to dump the bytes from _PyEval_EvalFrameDefault

Edited by shadow.Walker
Link to comment
Share on other sites

shadow.Walker
On 6/9/2020 at 3:22 PM, OdieWan said:

Thanks to "Extreme Coders", I've never programmed in python before, but after reading all your public material and following the recommended steps in this thread I've been able to desofuscate the code.
If they tell you how to do it you will understand it, but if they guide you and you have to discover how to do it you will learn

martisor_unpacked.py 10.3 kB · 12 downloads

Quote

def run_it():
    r"""
    /*
    An exception occurred when decompiling this method (06000001)

    ICSharpCode.Decompiler.DecompilerException: Error decompiling System.Void <Module>::.cctor()
    ---> System.OverflowException: Arithmetic operation resulted in an overflow.
    at ICSharpCode.Decompiler.ILAst.ILAstBuilder.StackSlot.ModifyStack(StackSlot[] stack, Int32 popCount, Int32 pushCount, ByteCode pushDefinition) in C:\projects\dnspy\Extensions\ILSpy.Decompiler\ICSharpCode.Decompiler\ICSharpCode.Decompiler\ILAst\ILAstBuilder.cs:line 47
    at ICSharpCode.Decompiler.ILAst.ILAstBuilder.StackAnalysis(MethodDef methodDef) in C:\projects\dnspy\Extensions\ILSpy.Decompiler\ICSharpCode.Decompiler\ICSharpCode.Decompiler\ILAst\ILAstBuilder.cs:line 387
    at ICSharpCode.Decompiler.ILAst.ILAstBuilder.Build(MethodDef methodDef, Boolean optimize, DecompilerContext context) in C:\projects\dnspy\Extensions\ILSpy.Decompiler\ICSharpCode.Decompiler\ICSharpCode.Decompiler\ILAst\ILAstBuilder.cs:line 269
    at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(IEnumerable`1 parameters, MethodDebugInfoBuilder& builder) in C:\projects\dnspy\Extensions\ILSpy.Decompiler\ICSharpCode.Decompiler\ICSharpCode.Decompiler\Ast\AstMethodBodyBuilder.cs:line 112
    at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDef methodDef, DecompilerContext context, AutoPropertyProvider autoPropertyProvider, IEnumerable`1 parameters, Boolean valueParameterIsKeyword, StringBuilder sb, MethodDebugInfoBuilder& stmtsBuilder) in C:\projects\dnspy\Extensions\ILSpy.Decompiler\ICSharpCode.Decompiler\ICSharpCode.Decompiler\Ast\AstMethodBodyBuilder.cs:line 88
    --- End of inner exception stack trace ---
    at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDef methodDef, DecompilerContext context, AutoPropertyProvider autoPropertyProvider, IEnumerable`1 parameters, Boolean valueParameterIsKeyword, StringBuilder sb, MethodDebugInfoBuilder& stmtsBuilder) in C:\projects\dnspy\Extensions\ILSpy.Decompiler\ICSharpCode.Decompiler\ICSharpCode.Decompiler\Ast\AstMethodBodyBuilder.cs:line 92
    at ICSharpCode.Decompiler.Ast.AstBuilder.<>c__DisplayClass89_1.<AddMethodBody>b__0() in C:\projects\dnspy\Extensions\ILSpy.Decompiler\ICSharpCode.Decompiler\ICSharpCode.Decompiler\Ast\AstBuilder.cs:line 1531
    */

    """
    pass

what Dnspy got to do with a python compiled program!! would u explain how u managed to modified the _PyEval_EvalFrameDefault function!

Link to comment
Share on other sites

Extreme Coders
15 hours ago, shadow.Walker said:

do u mind explaining how to do that? how to dump the bytes from _PyEval_EvalFrameDefault

_PyEval_EvalFrameDefault executes a code object on the Python frame.
To dump the code object to a file you need to use PyMarshal_WriteObjectToFile / PyMarshal_WriteObjectToString at an appropriate place within the function.

 

15 hours ago, shadow.Walker said:

what Dnspy got to do with a python compiled program!! would u explain how u managed to modified the _PyEval_EvalFrameDefault function!

DnSpy has nothing to do with Python. It's just a piece of string inserted there on purpose.

Edited by Extreme Coders
  • Like 3
  • Thanks 2
Link to comment
Share on other sites

  • 3 months later...
Extreme Coders

@bytemangl3r I can but doubt that will be of any help since it's compiled for Linux and isn't a generic solution against Pyarmor i.e. won't work against the recent versions.

  • Like 2
Link to comment
Share on other sites

  • 1 month later...
On 10/22/2020 at 4:19 AM, Extreme Coders said:

 I can but doubt that will be of any help since it's compiled for Linux and isn't a generic solution against Pyarmor i.e. won't work against the recent versions.

im on linux and it would be VERY helpfull if u could still send it

Edited by OliKing800
Link to comment
Share on other sites

  • 2 months later...
  • 1 month later...
On 6/9/2020 at 8:22 PM, OdieWan said:

Thanks to "Extreme Coders", I've never programmed in python before, but after reading all your public material and following the recommended steps in this thread I've been able to desofuscate the code.
If they tell you how to do it you will understand it, but if they guide you and you have to discover how to do it you will learn

martisor_unpacked.py 10.3 kB · 84 downloads

Perhaps a detailed explanation in performing this advanced operation would help fellow beginners like myself. :)

Link to comment
Share on other sites

  • 3 weeks later...
On 3/30/2020 at 2:50 AM, Extreme Coders said:

Not necessary to unpack to get the key.

Key:

  Hide contents

image.png.2846c516e23d847e927c7c7fd1ad3dd6.png

GENERATE-KEY-0X72GOD-UNPACKME

Converted it to run on Linux because it's easier to compile CPython on Linux and also because I don't have Visual Studio installed in the Windows VM.
This also explains why "title" and "cls" commands were not found.

Steps :

  Hide contents

 

1. Use pyinstxtractor.py to extract the executable in Python 3.7

2. Using the extracted files, create the following directory structure







.
|-- martisor.pyc
`-- pytransform
    |-- __init__.py
    |-- _pytransform.dll
    |-- license.lic
    `-- pytransform.key

1 directory, 5 files

For running on Linux, you need _pytransform.so downloadable from https://pyarmor.dashingsoft.com/platforms.html

3. Install psutil using pip (Required for pyarmor). From now on, you can just run python3.7 martisor.pyc instead of the unpackme executable.

4. pyarmor encrypts the code objects on disk and they are only decrypted at runtime just before they are executed. The entire logic is implemented in _pytransform.dll. There are anti-debugging/timing checks to prevent us from using a debugger to dump code objects from memory. But there's no need to use a debugger at all when CPython itself is open source. :)

5. Compile Python 3.7 from source. Modify the _PyEval_EvalFrameDefault function such that it dumps the code object to disk. By doing so we do not need to bother about all the anti-debugging and encrypted stuff. This is because pyarmor decrypts the code object in memory before it hands it to the Python VM for execution.

6. Run strings on the dumped code  object. We get many base64 strings. Like this one: CkdFTkVSQVRFLUtFWS0wWDcyR09ELVVOUEFDS01FCg==

7. Base64 decode and profit!

 

 

@Extreme Coders I couldn't found any __init__.py file after extracting? Please help me.

Link to comment
Share on other sites

Extreme Coders

@Dzung __init__.pyc is the same file as PYZ-00.pyz_extracted/pytransform.pyc after renaming it. Here I've further decompiled the pyc to py but that's not strictly necessary.

  • Like 1
Link to comment
Share on other sites

6 hours ago, Extreme Coders said:

@Dzung __init__.pyc is the same file as PYZ-00.pyz_extracted/pytransform.pyc after renaming it. Here I've further decompiled the pyc to py but that's not strictly necessary.

I got it. Thank you!

Link to comment
Share on other sites

  • 4 weeks later...
On 6/30/2020 at 2:18 PM, Extreme Coders said:

_PyEval_EvalFrameDefault executes a code object on the Python frame.
To dump the code object to a file you need to use PyMarshal_WriteObjectToFile / PyMarshal_WriteObjectToString at an appropriate place within the function.

 

DnSpy has nothing to do with Python. It's just a piece of string inserted there on purpose.

Hello

I try to use your idea,but I have two problems.

I use 

 PyMarshal_WriteObjectToFile

to dump, and this param have FILE, so I do not know how to get this FILE struct. I try to use fopen

2033997118_.png.66f32cce07866bfd8150f840197b0af8.png

Unfortunately, the gcc give me some error

problem1.png.3f65ff9c494829781e19257357cb02fc.png

And the last problem:

If I dump multiple script files, how to ensure that they will not be overwritten.

Please forgive me for the bad English. thanks for your help.

Link to comment
Share on other sites

Extreme Coders
  1. C is case-sensitive. FILE should be in uppercase.
  2. PyMarshal_WriteObjectToFile is defined in marshal.h. The header has to be #include 'd before
  3. To prevent overwriting, you can fopen in append mode, or make the filename a number and increase that sequentially on each call.

 

Link to comment
Share on other sites

uchiha_indra
On 5/15/2021 at 1:02 PM, Extreme Coders said:
  1. C is case-sensitive. FILE should be in uppercase.
  2. PyMarshal_WriteObjectToFile is defined in marshal.h. The header has to be #include 'd before
  3. To prevent overwriting, you can fopen in append mode, or make the filename a number and increase that sequentially on each call.

 

Hi! I followed your guide, and edited the file in the following way:

...
/* Start of code */

    /* push frame */
    if (Py_EnterRecursiveCall(""))
        return NULL;

    tstate->frame = f;
    FILE *dump_file = NULL;
    dump_file = fopen("./dump.log", "ab");
    PyMarshal_WriteObjectToFile((PyObject *) f, dump_file, 2);
    fclose(dump_file);

    if (tstate->use_tracing) {
...

 

However, when I execute the code and read the dump file, there are only '?' in them:

????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

Am I missing something?

Edited by uchiha_indra
Link to comment
Share on other sites

On 5/15/2021 at 3:32 PM, Extreme Coders said:
  1. C is case-sensitive. FILE should be in uppercase.
  2. PyMarshal_WriteObjectToFile is defined in marshal.h. The header has to be #include 'd before
  3. To prevent overwriting, you can fopen in append mode, or make the filename a number and increase that sequentially on each call.

 

Thanks for your help.

p1.png.f8973a123018594fc71fd26bc6b47274.png

I include marshal.h first, but the compiler give me more error. I google this that let me know repeated inclusion. The error follow below:

p2.png.727823a890355ec07efc096fb3562cc2.png

So, I think it can not include directly. I do not know how to do.... 

Thank you again.

Link to comment
Share on other sites

I just add 

extern PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int);

at ceval.c 's header. It can compile. It's amazing!

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...