skelsec/pypykatz

Unable to build valid Win64 PyInstaller version

1mm0rt41PC opened this issue · 7 comments

Hello,

I'm trying to build an Winx64 version but at the end I get a binary that don't have the live lsa.
Steps:

set py64=C:\python38\python.exe
%py64% -m pip install -U pip wheel ldap3 pywin32 pypiwin32
%py64% -m pip install -U tinyaes dnspython
%py64% -m pip install -U git+https://github.com/pyinstaller/pyinstaller
git clone https://github.com/skelsec/pypykatz
cd pypykatz
%py64% -m pip install minidump minikerberos aiowinreg msldap winsspi winacl pycryptodome
%py64% -m pip install git+https://github.com/skelsec/unicrypto
%py64% setup.py install

:: This version fail, but in 2021 that entry point worked
:: %py64% -m PyInstaller --onefile pypykatz\__main__.py --noupx

%py64% -m PyInstaller --onefile pypykatz\__amain__.py --noupx

The dist\__amain__.exe live lsa returns

usage: __amain__.exe live [-h] {process,token,users} ...
__amain__.exe live: error: argument module: invalid choice: 'lsa' (choose from 'process', 'token', 'users')

If I set the entry point to __main__.py and run the final binary I get:

Traceback (most recent call last):
  File "pypykatz\__main__.py", line 156, in <module>
  File "pypykatz\__main__.py", line 17, in main
  File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
  File "pypykatz\kerberos\cmdhelper.py", line 19, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
  File "pypykatz\kerberos\kerberos.py", line 7, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
  File "minikerberos\security.py", line 11, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
  File "minikerberos\aioclient.py", line 24, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
  File "minikerberos\protocol\encryption.py", line 57, in <module>
  File "PyInstaller\loader\pyimod02_importers.py", line 499, in exec_module
  File "unicrypto\symmetric.py", line 82, in <module>
  File "unicrypto\__init__.py", line 79, in get_preferred_cipher
  File "unicrypto\__init__.py", line 57, in get_cipher_by_name
  File "unicrypto\__init__.py", line 14, in import_from
ModuleNotFoundError: No module named 'unicrypto.backends.pycryptodomex'
[2276] Failed to execute script '__main__' due to unhandled exception!

How to build a working version for Winx64 ?

Hello,
yes that is a problem. Since moving to unicrypto compiling pypykatz into an executable is a bit more difficult, because unicrypto is dynamically loading/selecting one of the available crypto libraries. You'd need to explicitly install one crypto library then specify it to pyinstaller. It looks a bit ugly, but works if you put this in a bat file:

set hiddenimports= --hidden-import cryptography --hidden-import cffi --hidden-import cryptography.hazmat.backends.openssl --hidden-import cryptography.hazmat.bindings._openssl --hidden-import unicrypto --hidden-import unicrypto.backends.pycryptodome.DES --hidden-import  unicrypto.backends.pycryptodome.TDES --hidden-import unicrypto.backends.pycryptodome.AES --hidden-import unicrypto.backends.pycryptodome.RC4 --hidden-import unicrypto.backends.pure.DES --hidden-import  unicrypto.backends.pure.TDES --hidden-import unicrypto.backends.pure.AES --hidden-import unicrypto.backends.pure.RC4 --hidden-import unicrypto.backends.cryptography.DES --hidden-import  unicrypto.backends.cryptography.TDES --hidden-import unicrypto.backends.cryptography.AES --hidden-import unicrypto.backends.cryptography.RC4
python -m PyInstaller -F __main__.py --icon %~dp0progress\pypykatz\repo\pypykatz\pypykatz\buildtools\pypykatz.ico %hiddenimports%

no need to include all backends.
there are currently 6 backends in unicrypto:
pyCryptodomex, pyCryptodome, cryptography, pyCrypto, mbedtls, pure

but you may use only one backend. for include just that one:(mine is pycryptodome)
import unicrypto.backends.pycryptodome
in your app header and PyInstaller will correctly include all needed files.

Hello !

I'm still unable to build a valid binary. If I only use the hiddenimports I get the same error about ModuleNotFoundError: No module named 'unicrypto.backends.pycryptodomex'

set py64=C:\python310-x64\python.exe
%py64% -m pip install -U pip wheel ldap3 pywin32 pypiwin32 tinyaes dnspython pyinstaller
git clone https://github.com/skelsec/pypykatz
cd pypykatz
%py64% -m pip install minidump minikerberos aiowinreg msldap winsspi winacl pycryptodome
%py64% -m pip install unicrypto
%py64% setup.py install

set hiddenimports= --hidden-import cryptography --hidden-import cffi --hidden-import cryptography.hazmat.backends.openssl --hidden-import cryptography.hazmat.bindings._openssl --hidden-import unicrypto --hidden-import unicrypto.backends.pycryptodome.DES --hidden-import  unicrypto.backends.pycryptodome.TDES --hidden-import unicrypto.backends.pycryptodome.AES --hidden-import unicrypto.backends.pycryptodome.RC4 --hidden-import unicrypto.backends.pure.DES --hidden-import  unicrypto.backends.pure.TDES --hidden-import unicrypto.backends.pure.AES --hidden-import unicrypto.backends.pure.RC4 --hidden-import unicrypto.backends.cryptography.DES --hidden-import  unicrypto.backends.cryptography.TDES --hidden-import unicrypto.backends.cryptography.AES --hidden-import unicrypto.backends.cryptography.RC4

%py64% -m PyInstaller -F __main__.py %hiddenimports%

If I add some code inside __main__.py there is no more error but the process return nothing:
2022-09-26 12_11_26-215 143 318 - AnyDesk

I get the same behavior if I build without %hiddenimports% and with the code modification

You are right, this is indeed a bug. :( I'll try to fix it this week.

Update: I made the previous comment in a hurry, this is not a bug :)

set hiddenimports= --hidden-import cryptography --hidden-import cffi --hidden-import cryptography.hazmat.backends.openssl --hidden-import cryptography.hazmat.bindings._openssl --hidden-import unicrypto --hidden-import unicrypto.backends.pycryptodome.DES --hidden-import  unicrypto.backends.pycryptodome.TDES --hidden-import unicrypto.backends.pycryptodome.AES --hidden-import unicrypto.backends.pycryptodome.RC4 --hidden-import unicrypto.backends.pure.DES --hidden-import  unicrypto.backends.pure.TDES --hidden-import unicrypto.backends.pure.AES --hidden-import unicrypto.backends.pure.RC4 --hidden-import unicrypto.backends.cryptography.DES --hidden-import  unicrypto.backends.cryptography.TDES --hidden-import unicrypto.backends.cryptography.AES --hidden-import unicrypto.backends.cryptography.RC4 --hidden-import unicrypto.backends.pycryptodomex.DES --hidden-import  unicrypto.backends.pycryptodomex.TDES --hidden-import unicrypto.backends.pycryptodomex.AES --hidden-import unicrypto.backends.pycryptodomex.RC4

using the hidden imports I generated an executable that works just fine

I don't understand where my mistake is :/
I just redid a test in a clean VM in AppVeyor with the new hiddenimports variable, but the result is still a non-working binary

What version of python are you using?
Are you using exactly the same command lines for build ?

I found my error, the import unicrypto.backends.pycryptodomex was not added to the exe. I added this import in the var hiddenimports. It builds well now.

set py64=C:\python38\python.exe
%py64% -m pip install -U pip wheel ldap3 pywin32 pypiwin32
%py64% -m pip install -U tinyaes dnspython
%py64% -m pip install -U git+https://github.com/pyinstaller/pyinstaller
git clone https://github.com/skelsec/pypykatz
cd pypykatz
%py64% -m pip install minidump minikerberos aiowinreg msldap winsspi winacl pycryptodome
%py64% -m pip install git+https://github.com/skelsec/unicrypto
%py64% setup.py install

set hiddenimports= --hidden-import cryptography --hidden-import cffi --hidden-import cryptography.hazmat.backends.openssl --hidden-import cryptography.hazmat.bindings._openssl --hidden-import unicrypto --hidden-import unicrypto.backends.pycryptodome.DES --hidden-import  unicrypto.backends.pycryptodome.TDES --hidden-import unicrypto.backends.pycryptodome.AES --hidden-import unicrypto.backends.pycryptodome.RC4 --hidden-import unicrypto.backends.pure.DES --hidden-import  unicrypto.backends.pure.TDES --hidden-import unicrypto.backends.pure.AES --hidden-import unicrypto.backends.pure.RC4 --hidden-import unicrypto.backends.cryptography.DES --hidden-import  unicrypto.backends.cryptography.TDES --hidden-import unicrypto.backends.cryptography.AES --hidden-import unicrypto.backends.cryptography.RC4 --hidden-import unicrypto.backends.pycryptodomex.DES --hidden-import  unicrypto.backends.pycryptodomex.TDES --hidden-import unicrypto.backends.pycryptodomex.AES --hidden-import unicrypto.backends.pycryptodomex.RC4 --hidden-import unicrypto.backends.pycryptodomex

%py64% -m PyInstaller --onefile pypykatz\__main__.py --noupx %hiddenimports%