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 .@...s8...d.d.d.
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 ...