Obtained binaries from Discord server. The download link: https://drive.google.com/file/d/1xPP9R2VKmJ9jwNY_1xf1sVVHlxZIsLcg
Basic information about binaries. There are two main versions of the program in question:
aimful-kucoin.exe
and aimful-binance.exe
. They are both Windows executables. From the FAQ section of the discord server, the following information is available:
In what language was this bot written?
- Python.
- Extract the contents of the binary
git clone https://github.com/countercept/python-exe-unpacker.git
cd python-exe-unpacker
python pyinstxtractor.py ~/Downloads/Aimful/aimful-kucoin.exe
Install python decompiler called decompyle3
based on uncompyle6
:
git clone https://github.com/rocky/python-decompile3.git
cd python-decompile3
pip install -e .
- Attempt to decompile the contents of the binary
cd ./aimful-kucoin.exe_extracted/PYZ-00.pyz_extracted
decompyle3 ./kucoin.client.pyc
> ...
> ImportError: Ill-formed bytecode file ./kucoin.client.pyc
> <class 'ValueError'>; bad marshal data (unknown type code)
By searching for the file header "e3000000" on google, we can find this article: https://timonpeng.com/tips-of-pyinstaller-executable-file-decompilation/
- Inspect the struct file header bytes
xxd < struct | head -5
Output:
00000000: 420d 0d0a 0000 0000 7079 6930 1001 0000 B.......pyi0....
00000010: e300 0000 0000 0000 0000 0000 0008 0000 ................
00000020: 0040 0000 0073 3800 0000 6400 6401 6402 [email protected].
00000030: 6403 6404 6405 6406 6407 6708 5a00 6408 d.d.d.d.d.g.Z.d.
00000040: 6409 6c01 5400 6408 640a 6c01 6d02 5a02 d.l.T.d.d.l.m.Z.
Mainly we are interested in the first 16 bytes:
420d 0d0a 0000 0000 7079 6930 1001 0000
You can find that the first byte of the main program is
e3
, therefore, the contents beforee3
in the struct file are filled to the front of the main program file.
cp ./aiumful-kucoin ./aimful-kucoin.pyc
set pyc_file ./aimful-kucoin.pyc
# pad file with extra 4 bytes at the beginning
printf '\x00\x00\x00\x00' > $pyc_file.new
cat $pyc_file >> $pyc_file.new
mv $pyc_file.new $pyc_file
# replace the binary header with the 16 bytes above
printf '\x42\x0d\x0d\x0a\x00\x00\x00\x00\x70\x79\x69\x30\x10\x01\x00\x00' | dd of=$pyc_file bs=1 seek=0 count=16 conv=notrunc
- Attempt to decompile the binary
decompyle3 ./aimful-kucoin.pyc
Output:
# decompyle3 version 3.7.6
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.7.12 (default, Oct 9 2021, 17:28:41)
# [Clang 12.0.0 (clang-1200.0.32.29)]
# Embedded file name: dist\obf\aimful-kucoin.py
# Compiled at: 1995-09-27 10:18:56
# Size of source mod 2**32: 272 bytes
from pytransform import pyarmor_runtime
pyarmor_runtime()
__pyarmor__(__name__, __file__, b'PYARMOR\x00\x00\x03\x07\x00B\r\r\n\x06*\xa0\x01\x00\x00\x00\x00\x01\x00\x00\x00@\x00\x00\x00\x94\xa5\x01\x00\x00\x00\x00\x18>\x11
... binary obfuscated ...
From here we can deduce that the binary is obfuscated with the pytransform
library using pyarmor_runtime()
.
Quick search reveals there are some tools that can de-obfuscate the binary data.
git clone https://github.com/u0pattern/PyArmor-Deobfuscator.git
# copy PyArmorDeobfuscator.py to the working directory
# ...
decompyle3 ./aimful-kucoin.pyc > ./aimful-kucoin-obf.py
pip install uncompyle6
python ./PyArmorDeobfuscator.py -f ./pyimful-kucoin-obf.py -o ./aimful-kucoin.py
Output is:
[-] _pytransform.dll file not found [-]
At this point we need to start looking at the source code of the decompiler script. From the comment in the source code we can see that we need the following:
# please make sure you have _pytransform.dll and __init__.py in /dist/pytransform/ directory !!!
https://forum.tuts4you.com/topic/41945-python-pyarmor-my-protector/?tab=comments#comment-203008 From another article online, I found that using the extracted files, we can create the following directory structure:
.
|-- some-python-bytecode.pyc
`-- pytransform
|-- __init__.py
|-- _pytransform.dll
|-- _pytransform.dylib
1 directory, 5 files
The DLL was already included in the directory. For running on OSX I downloaded the pytransform library and placed it in the same directory as the script. https://pyarmor.dashingsoft.com/platforms.html
The contents of __init__.py
are:
from pytransform import pyarmor_runtime
pyarmor_runtime('/path/to/runtime')
as per docs at https://pyarmor.readthedocs.io/en/latest/understand-obfuscated-scripts.html
- Another attempt
python ./PyArmorDeobfuscator.py -f ./pyimful-kucoin-obf.py -o ./aimful-kucoin.py
Output is:
ImportError: File name: './aimful-kucoin-obf.pyc' doesn't exist
Rename aimful-kucoin.pyc
to aimful-kucoin-obf.pyc
and re-run the script.
The output is the same as the previous one, with a slight difference because this time we are using uncompyle6 to decompile the file.
# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.7.12 (default, Oct 9 2021, 17:28:41)
# [Clang 12.0.0 (clang-1200.0.32.29)]
# Embedded file name: dist\obf\aimful-kucoin.py
# Compiled at: 1995-09-27 10:18:56
# Size of source mod 2**32: 272 bytes
from pytransform import pyarmor_runtime
pyarmor_runtime()
__pyarmor__(__name__, __file__, b'PYARMOR\x00\x00\x03\x07\x00B\r\r\n\x06*\xa0\x01\x00\x00\x00\x00\x01\x00\x00\x00@\x00\x00\x00\x94\xa5\x01\x00\x00\x00\x00\x18>\x11\xb8\n\x00\x0
... binary obfuscated ...
but still after dump some part of compiled code object is encrypted by pyarmor,
it encrypts module and wrapping each class and methods which decrypts and restore codeobject by calling built-in funcation"pyarmor_enter" and after execute that frame encrypts again by calling "armor_exit", these both are built-in functions.