# Reverse Python Bytecode

Trong quá trình làm CTF ở giải AmateursCTF2023, tôi có gặp 1 bài trong mảng Reverse sử dụng file .pyc được biên dịch bởi python 3.10. Các bạn có thể tải challenge ở đây [trick-question.pyc](https://github.com/H4lst0n/CTF-Write-up/blob/main/AmateursCTF%202023/rev/rev_trickques/trick-question.pyc).

### Solutions

* Đầu tiên khi gặp 1 file .pyc ta sẽ sử dụng pydumpck để dump được ra file .py các bạn có thể xem thêm về pydumpck ở đây [pydumpck](https://github.com/serfend/pydumpck).
    
* Sau khi dump file ta có 1 folder output trong này sẽ xuất hiện file .py cần thiết của chúng ta.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690528731380/7e5b3e0d-3262-4895-9fe3-06a2b416e6d1.png align="center")
    
* Đây là code của chương trình sau khi dump thành công sau khi nhìn qua 1 lượt thì thấy có khả năng nó sẽ đảo ngược chuỗi rồi decode lại với base64 cho mình vì vậy tôi tiến hành fix và chạy code này.
    

```python
b64decode = lambda x: id.__self__.__dict__['exec'](id.__self__.__dict__['__import__']('base64').b64decode(x))
r = [0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0]
x = ['gIHByaW50KCJJbmNvcnJlY3QuIik=', 'gcHJpbnQoIkNvcnJlY3QhIikKZWxzZToKIC', 'CIgogOpkiIgozZhxmZgUGa0BiclRnbFJCK0VHculGKrNWZoNGImlmCp0HZpBiOnQWansHIsUGZvNGKps2Ylh2YoUGc5RHI9', 'yajVGajpgCpkCKgwSKo', 'xXHgwY1x4MDInLC', 'DecNGM4xlMwgHX2EDecFDM4x1YwgHXx', 'xXHgwNFx4MDJceDBjXHgwMVx4MDhceD', 'DecNGM4xlMwgHX2EDM4x1YwgHXy', 'xMlx4MDJceDBjXHgwMTJceD', 'DecNGM4xlMwgHXwEDecFDM4x1YwgHXy', 'DecBTM4xVMwgHXlBDecFDM4xFOxgHXx', 'DecVGM4xlMwgHXwEDecFDM4x1YwgHXy', 'DecJSMwgHXjBDecNDM4xlbx', 'xXHgwZVx4MDJceDE2XHgwMVx4MGNceD', 'xXHgwMlx4ODBceDBjXHgwMVx4MGNceD', 'Dec5GXx', 'DechDM4xVMwgHX4EDecJDM4xFNwgHXx', 'xXHgwY1x4MDFceDE0XHgwMlx4MGNceD', 'xXHgwY1x4MDFceDBjXHgwMVx4MGNceD', 'DecBTM4x1JiBCLz', 'nY2hlY2snLC', 'ncicsICdjJyksICcnLC', 'nc2h1ZmZsZScsICdmcm9tX2J5dGVzJywgJ3JhbmRpbnQnKSwgKCdpbnB1dCcsICd1bmRlcnNjb3JlcycsICdpJywgJ3gnLC', 'CLnQWZlN3JgwyJ0NXZnlGZ4VGan', 'nYXBwZW5kJywgJ2VuY29kZScsICdzcGxpdCcsICdzaGEyNTYnLC', 'CLn81X0NWak91Xn', 'nX19zZWxmX18nLC', 'nVHJ1ZScsICdEaWQgeW91IGtub3c/IHB5Y2RjIGNhbiBkZWNvbXBpbGUgbWFyc2hhbGVkIGNvZGUgb2JqZWN0cy4gSnVzdCBtYWtlIHN1cmUgeW91IG1lbnRpb24gdGhlIHJpZ2h0IHZlcnNpb24hJyksICgnaWQnLC', 'CLnMjZyYWY5YTZlljM4BzJgwyJ4VGan', 'CL4ITMgwiNgwiN4gjN4', 'zN3IDNgwyJw', 'DecdiYgwiMyETO5ETNygDIsgDIsEjN1', 'TM4cjMyQDIsUTOycjN5QTOyQDIscSZsRHdpx2JgwSNgwyJ05Wan', 'xMDgsIDUyKSwgNCwgYidmcmVlYmllJywgYicwZmZyZWViaWUnLC', 'CL5', 'TMgwiMwEDIskDOgwSO0gCIsMDIscCdzlGbn', 'CLn02bk5WYydCIscSY4YmYhR2YhNmZxMTN1IGOwI2Y4IzMkZ2MkFjMxQGNiJDMkFDN2gDNmRDO4YmNjFjNjZWMkRGNkdzN3cjMyIGNn', 'CLnIWash2chh2JgwyJf9Fdy9Gctl2XfdCIskCNz', 'sIDY4LC', 'jNxgCIsIDIsEDIscCUZdDaw42cnIGIs', 'DIscyXnIGIskSNz', 'sIDIzLC', 'xMywgMj', 'CLxEDIscDKgwyJfdCIscSZ0Fmcl1WduV2JgwiM0', 'CLn4WZsdCIscSfn', 'CLx0CIscSZzxWYGdCIscyeGR1QzJXdlRXYtF2JgwiMx', 'CLl52bOhCIscCMwgHXTBDM4xVOxgHXoQmMwgHXqFDM4xlaw', 'DecRHMwgHXTBDM4xVOxgHXz', 'walx4MDFqXHgwMmRceD', 'zXHg5MFx4MDFyXHg4MHRceD', 'Dect2JcRWMwgHXzgDecVDM4xFfw', 'xalx4MDJkJlx4MTlceD', 'DecpGMwgHX0NWcx', 'yN1x4MDB9XHgwNVx4OTBceD', 'DecxXNwgHX8VDM4xVfw', 'yfFx4MDVkJTlceD', 'Dec1nYwgHXdBDM4xFRw', '1fFx4MDBkJFx4MTlceD', 'Dec13YwgHXkBDM4x1Uw', 'DeclTM4x1MwgHXkJDM4xlax', 'xcl10XHgwMGpceD', 'wZCNrXHgwM1x4OTBceD', 'yfFx4MDRceGEwXHgwYmRceDBjZFx4MWVceGExXHgwMkFceD', 'DecFTY4xFZxgHXkBDM4x1NxgHXiQGMwgHX5EDecJDM4xVN4gHXx', 'walx4MDFqXHgwMmRceDFiXHgxOVx4MDBceGEwXG58XHgwMGRceDFjXHgxOVx4MDBkIGRceD', 'DecRHMwgHXTBDM4xVOxgHXz', 'walx4MDFqXHgwMmRceD', 'DecRHPyFDM4xFM5gHXz', 'DectWIkBDM4xVQy', 'walx4MDFqXHgwMmRceDFiXHgxOVx4MDBceGEwXG58XHgwMGRceDFjXHgxOVx4MDBkXHgxOGQgXHg4NVx4MDJceDE5XHgwMGRceDFkXHhhMVx4MDJ8XHgwNFx4YTBceDBiZFx4MGNkXHgxZVx4YTFceD', 'DecRHMwgHXTBDM4xVOxgHXz', 'walx4MDFqXHgwMmRceD', 'DecRHZxgHXyFDM4xFM5gHXz', 'DectmZxgHXkBDM4xVQy', 'walx4MDFqXHgwMmRceDFiXHgxOVx4MDBceGEwXG58XHgwMGRceDFjXHgxOVx4MDBkXHgwY2RceDE4XHg4NVx4MDJceDE5XHgwMGRceDFkXHhhMVx4MDJ8XHgwNFx4YTBceDBiZFx4MGNkXHgxZVx4YTFceD', 'DecRHMwgHXTBDM4xVOxgHXz', 'DecRmMwgHXqFDM4xlaw', 'DecRXZmhHXyNDM4x1ahFDecRGMwgHX3EDeclTM4xFZw', 'DeclTM4xFOxgHXkBDM4xFfw', 'DecNFMwgHX5EDecNDM4xFZy', 'DecpWMwgHXqBDM4xFdwYGecJ3MwgHXrFDM4xlMhhHX3EDecRGMwgHXnBDM4xVOxgHX2EDecRGMwgHX8BDM4xVMwgHXx', 'wZFx4MTZceDE5XHgwMFx4YTFceD', 'wXHg4M1x4MDF8XHgwMGRceDE2PFx4MDB8XHgwNFx4YTBcdHxceD', 'wfFx4MDBkXHgxNlx4MTlceD', 'DeclTM4xlcz', 'Dect2MxgHXkBDM4xVMhhHX3', 'xXHhhMFx4MDZ8XHgwMGRceDBmXHgxOVx4MDBceGExXHgwMVx4YTBceD', 'DecNDO4xlMxgHXkBDM4xVOxgHXxEDecRmMwgHXqFDM4xlaw', 'zXHgxOVx4MDBTXHgwMHRceD', 'walx4MDFqXHgwMmRceD', 'DecRXOhhHXyNDM4x1awEDecR2MwgHXmBDM4xFOxgHXw', 'wXHgxN1x4MDB8XHgwMGRceDBlXHgxOVx4MDBkXHgwZVx4MTlceD', 'wZFx4MGVceDE5XHgwMGRceDBmXHgxOVx4MDB8XHgwMGRceDBlXHgxOVx4MDBkXHgwY1x4MTlceD', 'DecxHMwgHX4EDecBDM4xVOxgHXjBDecRGMwgHX5EDecVGM4xFZw', 'DecxHMwgHX3EDecBDM4xVOxgHXmBDecRGMwgHX5EDecVGM4xFZw', 'wZFx4MGVceDE5XHgwMHxceD', 'wfFx4MDBkXHgwZVx4MTlceD', 'wZFx4MGZceDE5XHgwMFx4MThceD', 'wfFx4MDBkXHgwZVx4MTlceD', 'wZFx4MGVceDE5XHgwMFx4MTdceD', 'DeclTM4xVZwgHXkBDM4xFfw', 'DeclTM4x1YwgHXkBDM4xVOxgHXlBDecRGMwgHX8BDM4x1Uw', 'xalx4MDJkXHgwM1x4MTlceD', 'zcmx0XHgwMGpceD', '0XHg4NVx4MDNceDE5XHgwMGRccmtceD', 'wZFx4MDBkXHgwMGRceD', 'wfFx4MDBkXHgwY1x4MTlceD', 'Dec1XMwgHXxEGecJGM4xFZ1', 'DecBTY4xFMwgHXxEGecRDM4xFMhhHXw', 'zXHgxOVx4MDBTXHgwMHxceD', 'DecRmMwgHXqFDM4xlaw', 'xa1x4MDNyVHRceD', 'xXHgwMHE6fFx4MDFnXHgwMGRcblx4YTJceD', 'yXHhhMVx4MDFceD', 'Decx3MwgHXwEGecFDM4xFfHJnMwgHXrRHXkNDM4xFfz', 'xRFx4MDBdXHJcXFx4MDJ9XHgwMn1ceD', '4XHgxOVx4MDB8XHgwMFx4ODNceD', 'DecRmMwgHXqFDM4xlaw', 'DecRXMwgHX9BDM4x1Zw', 'DecNFMwgHX5EDecNDM4xFZy', 'DecpWMwgHXqBDM4xFdwI3MwgHXrdDM4xFZx', '2XHgxOVx4MDB8XHgwMFx4ODNceD', 'DecRmMwgHXqFDM4xlaw', 'DecRHMwgHX9BDM4xVOxgHXy', 'wZFx4MDFkXHgwNFx4ODVceD', 'DecxHMwgHXTBDM4xVOxgHXz', 'DecRmMwgHXqFDM4xlaw', 'DecRXYxgHXyNDM4x1a1', 'wZFx4MDRceDE5XHgwMGRceD', 'zXHgxOVx4MDBTXHgwMHxceD', 'DecRmMwgHXqFDM4xlaw', 'ya1x4MDNyXHgwZXRceD', 'xXHg4NVx4MDJceDE5XHgwMGRceD', 'Y2hlY2sgPSBsYW1iZGE6Tm9uZQpjb2RlID0gdHlwZShjaGVjay5fX2NvZGVfXykoMSwgMCwgMCwgNiwgNSwgNjcsIGInfFx4MDBkXHgwMGRceD']
for i in range(len(r)):
    if r[i]:
        x[i] = x[i][::-1]
b64decode('A'.join(x[::-1]))
```

* Tại đây ta sẽ sửa file và ghi output khi chạy file python này ra 1 file mới .
    

```python
import base64

def b64decode(x):
    return base64.b64decode(x)
r = [0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0]
x = ['gIHByaW50KCJJbmNvcnJlY3QuIik=', 'gcHJpbnQoIkNvcnJlY3QhIikKZWxzZToKIC', 'CIgogOpkiIgozZhxmZgUGa0BiclRnbFJCK0VHculGKrNWZoNGImlmCp0HZpBiOnQWansHIsUGZvNGKps2Ylh2YoUGc5RHI9', 'yajVGajpgCpkCKgwSKo', 'xXHgwY1x4MDInLC', 'DecNGM4xlMwgHX2EDecFDM4x1YwgHXx', 'xXHgwNFx4MDJceDBjXHgwMVx4MDhceD', 'DecNGM4xlMwgHX2EDM4x1YwgHXy', 'xMlx4MDJceDBjXHgwMTJceD', 'DecNGM4xlMwgHXwEDecFDM4x1YwgHXy', 'DecBTM4xVMwgHXlBDecFDM4xFOxgHXx', 'DecVGM4xlMwgHXwEDecFDM4x1YwgHXy', 'DecJSMwgHXjBDecNDM4xlbx', 'xXHgwZVx4MDJceDE2XHgwMVx4MGNceD', 'xXHgwMlx4ODBceDBjXHgwMVx4MGNceD', 'Dec5GXx', 'DechDM4xVMwgHX4EDecJDM4xFNwgHXx', 'xXHgwY1x4MDFceDE0XHgwMlx4MGNceD', 'xXHgwY1x4MDFceDBjXHgwMVx4MGNceD', 'DecBTM4x1JiBCLz', 'nY2hlY2snLC', 'ncicsICdjJyksICcnLC', 'nc2h1ZmZsZScsICdmcm9tX2J5dGVzJywgJ3JhbmRpbnQnKSwgKCdpbnB1dCcsICd1bmRlcnNjb3JlcycsICdpJywgJ3gnLC', 'CLnQWZlN3JgwyJ0NXZnlGZ4VGan', 'nYXBwZW5kJywgJ2VuY29kZScsICdzcGxpdCcsICdzaGEyNTYnLC', 'CLn81X0NWak91Xn', 'nX19zZWxmX18nLC', 'nVHJ1ZScsICdEaWQgeW91IGtub3c/IHB5Y2RjIGNhbiBkZWNvbXBpbGUgbWFyc2hhbGVkIGNvZGUgb2JqZWN0cy4gSnVzdCBtYWtlIHN1cmUgeW91IG1lbnRpb24gdGhlIHJpZ2h0IHZlcnNpb24hJyksICgnaWQnLC', 'CLnMjZyYWY5YTZlljM4BzJgwyJ4VGan', 'CL4ITMgwiNgwiN4gjN4', 'zN3IDNgwyJw', 'DecdiYgwiMyETO5ETNygDIsgDIsEjN1', 'TM4cjMyQDIsUTOycjN5QTOyQDIscSZsRHdpx2JgwSNgwyJ05Wan', 'xMDgsIDUyKSwgNCwgYidmcmVlYmllJywgYicwZmZyZWViaWUnLC', 'CL5', 'TMgwiMwEDIskDOgwSO0gCIsMDIscCdzlGbn', 'CLn02bk5WYydCIscSY4YmYhR2YhNmZxMTN1IGOwI2Y4IzMkZ2MkFjMxQGNiJDMkFDN2gDNmRDO4YmNjFjNjZWMkRGNkdzN3cjMyIGNn', 'CLnIWash2chh2JgwyJf9Fdy9Gctl2XfdCIskCNz', 'sIDY4LC', 'jNxgCIsIDIsEDIscCUZdDaw42cnIGIs', 'DIscyXnIGIskSNz', 'sIDIzLC', 'xMywgMj', 'CLxEDIscDKgwyJfdCIscSZ0Fmcl1WduV2JgwiM0', 'CLn4WZsdCIscSfn', 'CLx0CIscSZzxWYGdCIscyeGR1QzJXdlRXYtF2JgwiMx', 'CLl52bOhCIscCMwgHXTBDM4xVOxgHXoQmMwgHXqFDM4xlaw', 'DecRHMwgHXTBDM4xVOxgHXz', 'walx4MDFqXHgwMmRceD', 'zXHg5MFx4MDFyXHg4MHRceD', 'Dect2JcRWMwgHXzgDecVDM4xFfw', 'xalx4MDJkJlx4MTlceD', 'DecpGMwgHX0NWcx', 'yN1x4MDB9XHgwNVx4OTBceD', 'DecxXNwgHX8VDM4xVfw', 'yfFx4MDVkJTlceD', 'Dec1nYwgHXdBDM4xFRw', '1fFx4MDBkJFx4MTlceD', 'Dec13YwgHXkBDM4x1Uw', 'DeclTM4x1MwgHXkJDM4xlax', 'xcl10XHgwMGpceD', 'wZCNrXHgwM1x4OTBceD', 'yfFx4MDRceGEwXHgwYmRceDBjZFx4MWVceGExXHgwMkFceD', 'DecFTY4xFZxgHXkBDM4x1NxgHXiQGMwgHX5EDecJDM4xVN4gHXx', 'walx4MDFqXHgwMmRceDFiXHgxOVx4MDBceGEwXG58XHgwMGRceDFjXHgxOVx4MDBkIGRceD', 'DecRHMwgHXTBDM4xVOxgHXz', 'walx4MDFqXHgwMmRceD', 'DecRHPyFDM4xFM5gHXz', 'DectWIkBDM4xVQy', 'walx4MDFqXHgwMmRceDFiXHgxOVx4MDBceGEwXG58XHgwMGRceDFjXHgxOVx4MDBkXHgxOGQgXHg4NVx4MDJceDE5XHgwMGRceDFkXHhhMVx4MDJ8XHgwNFx4YTBceDBiZFx4MGNkXHgxZVx4YTFceD', 'DecRHMwgHXTBDM4xVOxgHXz', 'walx4MDFqXHgwMmRceD', 'DecRHZxgHXyFDM4xFM5gHXz', 'DectmZxgHXkBDM4xVQy', 'walx4MDFqXHgwMmRceDFiXHgxOVx4MDBceGEwXG58XHgwMGRceDFjXHgxOVx4MDBkXHgwY2RceDE4XHg4NVx4MDJceDE5XHgwMGRceDFkXHhhMVx4MDJ8XHgwNFx4YTBceDBiZFx4MGNkXHgxZVx4YTFceD', 'DecRHMwgHXTBDM4xVOxgHXz', 'DecRmMwgHXqFDM4xlaw', 'DecRXZmhHXyNDM4x1ahFDecRGMwgHX3EDeclTM4xFZw', 'DeclTM4xFOxgHXkBDM4xFfw', 'DecNFMwgHX5EDecNDM4xFZy', 'DecpWMwgHXqBDM4xFdwYGecJ3MwgHXrFDM4xlMhhHX3EDecRGMwgHXnBDM4xVOxgHX2EDecRGMwgHX8BDM4xVMwgHXx', 'wZFx4MTZceDE5XHgwMFx4YTFceD', 'wXHg4M1x4MDF8XHgwMGRceDE2PFx4MDB8XHgwNFx4YTBcdHxceD', 'wfFx4MDBkXHgxNlx4MTlceD', 'DeclTM4xVNxgHXkJDM4xlax', 'DecpGMwgHX0BDM4xVMwgHXx', 'DecFTY4xFMwgHX5EDecZGM4xFZw', 'DecxHOwgHXwEGecRDM4xFf0', 'wZFx4MTRceDgzXHgwMX1ceD', 'DeclTM4xVMxgHXkJDM4xlax', 'DecpGMwgHX0BDM4x1Uw', 'DeclTM4x1MwgHXkJDM4xlax', 'DecpGMwgHX0BzY4xlcz', 'Dect2MxgHXkBDM4xVMhhHX3', 'xXHhhMFx4MDZ8XHgwMGRceDBmXHgxOVx4MDBceGExXHgwMVx4YTBceD', 'DecNDO4xlMxgHXkBDM4xVOxgHXxEDecRmMwgHXqFDM4xlaw', 'zXHgxOVx4MDBTXHgwMHRceD', 'walx4MDFqXHgwMmRceD', 'DecRXOhhHXyNDM4x1awEDecR2MwgHXmBDM4xFOxgHXw', 'wXHgxN1x4MDB8XHgwMGRceDBlXHgxOVx4MDBkXHgwZVx4MTlceD', 'wZFx4MGVceDE5XHgwMGRceDBmXHgxOVx4MDB8XHgwMGRceDBlXHgxOVx4MDBkXHgwY1x4MTlceD', 'DecxHMwgHX4EDecBDM4xVOxgHXjBDecRGMwgHX5EDecVGM4xFZw', 'DecxHMwgHX3EDecBDM4xVOxgHXmBDecRGMwgHX5EDecVGM4xFZw', 'wZFx4MGVceDE5XHgwMHxceD', 'wfFx4MDBkXHgwZVx4MTlceD', 'wZFx4MGZceDE5XHgwMFx4MThceD', 'wfFx4MDBkXHgwZVx4MTlceD', 'wZFx4MGVceDE5XHgwMFx4MTdceD', 'DeclTM4xVZwgHXkBDM4xFfw', 'DeclTM4x1YwgHXkBDM4xVOxgHXlBDecRGMwgHX8BDM4x1Uw', 'xalx4MDJkXHgwM1x4MTlceD', 'zcmx0XHgwMGpceD', '0XHg4NVx4MDNceDE5XHgwMGRccmtceD', 'wZFx4MDBkXHgwMGRceD', 'wfFx4MDBkXHgwY1x4MTlceD', 'Dec1XMwgHXxEGecJGM4xFZ1', 'DecBTY4xFMwgHXxEGecRDM4xFMhhHXw', 'zXHgxOVx4MDBTXHgwMHxceD', 'DecRmMwgHXqFDM4xlaw', 'xa1x4MDNyVHRceD', 'xXHgwMHE6fFx4MDFnXHgwMGRcblx4YTJceD', 'yXHhhMVx4MDFceD', 'Decx3MwgHXwEGecFDM4xFfHJnMwgHXrRHXkNDM4xFfz', 'xRFx4MDBdXHJcXFx4MDJ9XHgwMn1ceD', '4XHgxOVx4MDB8XHgwMFx4ODNceD', 'DecRmMwgHXqFDM4xlaw', 'DecRXMwgHX9BDM4x1Zw', 'DecNFMwgHX5EDecNDM4xFZy', 'DecpWMwgHXqBDM4xFdwI3MwgHXrdDM4xFZx', '2XHgxOVx4MDB8XHgwMFx4ODNceD', 'DecRmMwgHXqFDM4xlaw', 'DecRHMwgHX9BDM4xVOxgHXy', 'wZFx4MDFkXHgwNFx4ODVceD', 'DecxHMwgHXTBDM4xVOxgHXz', 'DecRmMwgHXqFDM4xlaw', 'DecRXYxgHXyNDM4x1a1', 'wZFx4MDRceDE5XHgwMGRceD', 'zXHgxOVx4MDBTXHgwMHxceD', 'DecRmMwgHXqFDM4xlaw', 'ya1x4MDNyXHgwZXRceD', 'xXHg4NVx4MDJceDE5XHgwMGRceD', 'Y2hlY2sgPSBsYW1iZGE6Tm9uZQpjb2RlID0gdHlwZShjaGVjay5fX2NvZGVfXykoMSwgMCwgMCwgNiwgNSwgNjcsIGInfFx4MDBkXHgwMGRceD']

for i in range(len(r)):
    if r[i]:
        x[i] = x[i][::-1]

result = b64decode('A'.join(x[::-1]))
print(result)
with open('solve.py', 'w') as file:
    file.write(result.decode('utf-8'))
```

* Đây chính là đoạn code sau khi ta chạy file nó đã gen ra những bytecode trong python và có 1 chuỗi làm tôi chú ý đến 'Did you know? pycdc can decompile marshaled code objects. Just make sure you mention the right version!'. Có thể tác giả của bài này đang hướng tôi đến việc sử dụng pycdc để decompile lại file ban đầu bằng những bytecode. Nhưng lúc này tôi vẫn chưa biết bytecode là gì 😞.
    

```python
check = lambda:None
code = type(check.__code__)(1, 0, 0, 6, 5, 67, b'|\x00d\x00d\x01\x85\x02\x19\x00d\x02k\x03r\x0et\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x04\x19\x00d\x05k\x03r\x1at\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x01d\x04\x85\x02\x19\x00}\x00t\x00j\x01j\x02d\x06\x19\x00|\x00\x83\x01d\x07k\x03r0t\x00j\x01j\x02d\x03\x19\x00S\x00g\x00}\x01t\x00j\x01j\x02d\x08\x19\x00|\x00\x83\x01D\x00]\r\\\x02}\x02}\x03|\x03d\tk\x02rG|\x01\xa0\x03|\x02\xa1\x01\x01\x00q:|\x01g\x00d\n\xa2\x01k\x03rTt\x00j\x01j\x02d\x03\x19\x00S\x00|\x00\xa0\x04\xa1\x00\xa0\x05d\x0b\xa1\x01}\x00|\x00d\x0c\x19\x00d\x00d\x00d\x04\x85\x03\x19\x00d\rk\x03rlt\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x0e\x19\x00d\x0c\x19\x00|\x00d\x0e\x19\x00d\x0e\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0f\x19\x00\x18\x00|\x00d\x0e\x19\x00d\x0e\x19\x00|\x00d\x0e\x19\x00d\x0f\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0c\x19\x00\x18\x00|\x00d\x0e\x19\x00d\x0f\x19\x00|\x00d\x0e\x19\x00d\x0c\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0e\x19\x00\x18\x00f\x03d\x10k\x03r\xa9t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x11\x19\x00d\x12\x83\x01\xa0\x06|\x00d\x0f\x19\x00\xa1\x01\xa0\x07\xa1\x00d\x13k\x03r\xc0t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x11\x19\x00d\x14\x83\x01}\x04|\x04\xa0\x08|\x00d\x0f\x19\x00\xa1\x01\x01\x00t\x00j\x01j\x02d\x15\x19\x00|\x00d\x16\x19\x00\x83\x01|\x00d\x16<\x00|\x04\xa0\t|\x00d\x16\x19\x00\xa1\x01\x01\x00|\x00d\x16\x19\x00g\x00d\x17\xa2\x01k\x03r\xf0t\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x18\x19\x00d\x19\x17\x00d\x1ak\x03r\xfet\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d\x0cd\x18\x85\x02\x19\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d\x1fk\x03\x90\x01r\x1dt\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d\x18d \x85\x02\x19\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d!k\x03\x90\x01r<t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d d\x01\x85\x02\x19\x00d"\x17\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d#k\x03\x90\x01r]t\x00j\x01j\x02d\x03\x19\x00S\x00d\x0c}\x05|\x00d$\x19\x00D\x00]\x0b}\x02|\x05d%9\x00}\x05|\x05|\x027\x00}\x05\x90\x01qct\x00j\x01j\x02d&\x19\x00|\x05\x83\x01d\'k\x03\x90\x01r\x80t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d(\x19\x00S\x00', (None, 12, 'amateursCTF{', 'False', -1, '}', 'len', 42, 'enumerate', '_', (7, 11, 13, 20, 23, 35), b'_', 0, b'sn0h7YP', 1, 2, (160, 68, 34), '__import__', 'hashlib', '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a', 'random', 'list', 3, (49, 89, 102, 109, 108, 52), 4, b'freebie', b'0ffreebie', 'int', 5, 'little', 4294967295, 4227810561, 8, 825199122, b'\x00', 4277086886, 6, 128, 'hex', '0x29ee69af2f3', 'True', 'Did you know? pycdc can decompile marshaled code objects. Just make sure you mention the right version!'), ('id', '__self__', '__dict__', 'append', 'encode', 'split', 'sha256', 'hexdigest', 'seed', 'shuffle', 'from_bytes', 'randint'), ('input', 'underscores', 'i', 'x', 'r', 'c'), '', 'check', 3, b'\x10\x01\x0c\x01\x0c\x01\x0c\x01\x0c\x01\x14\x02\x0c\x01\x04\x02\x18\x01\x08\x01\n\x01\x02\x80\x0c\x01\x0c\x01\x0e\x02\x16\x01\x0c\x01n\x03\x0c\x01"\x02\x0c\x01\x10\x02\x0e\x01\x18\x01\x0e\x01\x10\x02\x0c\x01\x10\x02\x0c\x012\x02\x0c\x012\x02\x0c\x016\x02\x0c\x01\x04\x02\x0c\x01\x08\x01\x0c\x01\x16\x02\x0c\x01\x0c\x02', (), ())

check = type(check)(code, {'id': id})
if check(input("Enter the flag: ")):
    print("Correct!")
else:
    print("Incorrect.")
```

* Tôi đã tìm hiểu 1 lúc và tóm tắt lại được 1 số chú ý. Bytecode trong Python là một dạng mã trung gian (intermediate code) được sử dụng bởi trình thông dịch Python để thực thi các chương trình Python. Khi bạn viết mã Python, trình thông dịch sẽ chuyển đổi mã nguồn Python của bạn thành bytecode trước khi thực thi mã. Bytecode là một dạng mã hợp ngữ giống như mã máy, nhưng thay vì chạy trực tiếp trên máy tính, nó sẽ chạy trong môi trường của trình thông dịch Python.
    

Dưới đây là một số thông tin cơ bản về bytecode Python:

1. **Định dạng bytecode**: Bytecode Python là một chuỗi các mã byte (bytecode) duy nhất. Mỗi bytecode thể hiện một hoạt động cụ thể mà trình thông dịch Python thực hiện. Ví dụ, có bytecode cho việc gán giá trị, tính toán, thực thi các hàm, kiểm tra điều kiện, v.v.
    
2. **Độc lập nền tảng**: Bytecode Python là độc lập nền tảng, điều đó có nghĩa là bạn có thể viết mã Python trên một nền tảng như Windows và chạy nó trên một nền tảng khác như Linux hoặc macOS mà không cần viết lại mã nguồn. Điều này được thực hiện bởi trình thông dịch Python, giúp code Python trở nên di động và dễ dàng chạy trên nhiều hệ điều hành.
    
3. **Tốc độ thực thi**: Bytecode Python được thiết kế để giảm độ phức tạp của việc thực thi mã nguồn Python so với việc thực thi mã nguồn gốc. Mã bytecode thường nhanh hơn khi thực thi, do đó giúp cải thiện hiệu suất trong quá trình chạy mã Python.
    
4. **PVM - Python Virtual Machine**: Python Virtual Machine (PVM) là một phần mềm giả lập máy ảo mà thực thi bytecode Python. Khi bạn chạy một chương trình Python, trình thông dịch sẽ sử dụng PVM để thực thi bytecode.
    
5. **.pyc và .pyo files**: Khi bạn chạy một chương trình Python, trình thông dịch sẽ biên dịch mã nguồn thành bytecode và lưu trữ nó trong các tệp có đuôi .pyc (Python Compiled) hoặc .pyo (Python Optimized). Các tệp này sẽ được sử dụng lần sau bạn chạy chương trình, giúp giảm thời gian biên dịch lại mã nguồn.
    
6. **Disassembly**: Bạn có thể xem mã bytecode của một module Python bằng cách sử dụng module `dis`. Module này cung cấp các công cụ giúp bạn hiểu cách bytecode hoạt động.
    
7. **Đọc và ghi bytecode**: Nếu bạn muốn tùy chỉnh hoặc xử lý bytecode trực tiếp, Python cung cấp các module như `marshal` để đọc và ghi bytecode từ và vào các tệp.
    

* Cùng theo hướng của tác giả sau khi tìm 1 số tools decompile bytecode python thì tôi thấy tại đây [Pycdc](https://github.com/zrax/pycdc) được recommend nhiều nhất.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690530178552/aefa1c33-f72b-4093-8862-7584ed318899.png align="center")
    
* Theo hướng dẫn thì ta sẽ sử dụng marshal.dumps để biên dịch ra file .pyc sau đó sẽ dump lại ra file .py với version 3.10 của python. Tiến hành sửa code từ chương trình cũ.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690530764508/8a9a025c-95ca-419a-978f-1422b0c0d3d6.png align="center")
    
* Đến đây ta đã có file dumps.pyc =&gt; thực hiện dump ra file .py với version 10. Theo hướng dẫn ở trên ta sẽ sử dụng pycdc để decompile.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690530900572/48208ca8-3095-4efb-bef8-078e207ef96e.png align="center")
    
* Đây chính là phần code đầy đủ của chương trình. Nếu bạn vẫn cảm thấy quá khó đọc thì ta sẽ sử dụng chatGPT để sửa lại code cho dễ đọc hơn. Đây là phiên bản code sau khi đã qua tay của chatGPT và đừng quên phần input đã comment ở bên trên.
    

```python
def validate_flag(input_flag):
    if input_flag[:12] != 'amateursCTF{':
        return False
    if input_flag[-1] != '}':
        return False
    
    input_flag = input_flag[12:-1]
    if len(input_flag) != 42:
        return False

    underscores = []
    for i, x in enumerate(input_flag):
        if x == '_':
            underscores.append(i)

    if underscores != [7, 11, 13, 20, 23, 35]:
        return False

    input_parts = input_flag.encode().split(b'_')
    if input_parts[0][::-1] != b'sn0h7YP':
        return False

    if (input_parts[1][0] + input_parts[1][1] - input_parts[1][2], input_parts[1][1] + input_parts[1][2] - input_parts[1][0], input_parts[1][2] + input_parts[1][0] - input_parts[1][1]) != (160, 68, 34):
        return False

    import hashlib
    if hashlib.sha256(input_parts[2]).hexdigest() != '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a':
        return False

    import random
    random.seed(input_parts[2])
    input_parts[3] = list(input_parts[3])
    random.shuffle(input_parts[3])

    if input_parts[3] != [49, 89, 102, 109, 108, 52]:
        return False

    if input_parts[4] + b'freebie' != b'0ffreebie':
        return False

    xor_results = [
        int.from_bytes(input_parts[5][0:4], 'little') ^ random.randint(0, 0xFFFFFFFF),
        int.from_bytes(input_parts[5][4:8], 'little') ^ random.randint(0, 0xFFFFFFFF),
        int.from_bytes(input_parts[5][8:12], 'little') ^ random.randint(0, 0xFFFFFFFF)
    ]

    if xor_results != [0xFBFF4501, 825199122, 0xFEEF2AA6]:
        return False

    c = 0
    for i in input_parts[6]:
        c *= 128
        c += i

    if hex(c) != '0x29ee69af2f3':
        return False

    return True

user_input = input("Flag: ")
if validate_flag(user_input):
    print("Correct")
else:
    print("Incorrect")
```

* Đến đây cũng cảm thấy khá nhẹ nhàng rồi ta sẽ reverse từng đoạn code 1. Đầu tiên input sẽ check xem 12 kí tự đầu tiên có phải là `amateursCTF{` và kí tự cuối có phải là \`}\` hay không.
    
    ```python
    if input_flag[:12] != 'amateursCTF{':
        return False
    if input_flag[-1] != '}':
        return False
    ```
    
* Tiếp theo input sẽ cắt chuỗi bỏ phần đầu đi 12 kí tự và số lượng kí tự của flag còn lại là 42 kí tự. Sau đó nó sẽ append những vị trí có dấu \`\_\` cho flag.
    
    ```python
    input_flag = input_flag[12:-1]
    if len(input_flag) != 42:
        return False
    
    underscores = []
    for i, x in enumerate(input_flag):
        if x == '_':
            underscores.append(i)
    
    if underscores != [7, 11, 13, 20, 23, 35]:
        return False
    ```
    
    ```python
    input_parts = input_flag.encode().split(b'_')
        if input_parts[0][::-1] != b'sn0h7YP':
            return False
    
        if (input_parts[1][0] + input_parts[1][1] - input_parts[1][2], input_parts[1][1] + input_parts[1][2] - input_parts[1][0], input_parts[1][2] + input_parts[1][0] - input_parts[1][1]) != (160, 68, 34):
            return False
    ```
    
* Lúc này flag sẽ được cắt làm 7 phần vì có 6 dấu \_ xét phần thứ nhất nó bị đảo ngược chuỗi vậy nên lúc này `part[0]` của nó sẽ mang giá trị là `PY7h0ns` .
    
* FLag lúc này `amateursCTF{PY7h0ns_xxx_x_xxxxxx_xx_xxxxxxxxxxx_xxxxxx}`.
    
* Tiếp theo ta sẽ xử lý `part[1]` với `z3solver`.
    
    ```python
    from z3 import *
    
    a = Int('a')
    b = Int('b')
    c = Int('c')
    
    val = [
        a + b - c == 160,
        b + c - a == 68,
        c + a - b == 34
    ]
    
    s = Solver()
    s.add(val)
    
    if s.check() == sat:
        key = s.model()
        ar = key[a].as_long()
        br = key[b].as_long()
        cr = key[c].as_long()
        print(chr(ar) + chr(br) + chr(cr))
    else:
        print("ko co")
    ```
    
* Sau khi chạy code ta được chuỗi `ar3`.
    
* FLag lúc này `amateursCTF{PY7h0ns_ar3_x_xxxxxx_xx_xxxxxxxxxxx_xxxxxx}`
    
    ```python
    import hashlib
    if hashlib.sha256(input_parts[2]).hexdigest() != '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a':
        return False
    
    import random
    random.seed(input_parts[2])
    input_parts[3] = list(input_parts[3])
    random.shuffle(input_parts[3])
    
    if input_parts[3] != [49, 89, 102, 109, 108, 52]:
        return False
    
    if input_parts[4] + b'freebie' != b'0ffreebie':
        return False
    
    xor_results = [
            int.from_bytes(input_parts[5][0:4], 'little') ^ random.randint(0, 0xFFFFFFFF),
            int.from_bytes(input_parts[5][4:8], 'little') ^ random.randint(0, 0xFFFFFFFF),
            int.from_bytes(input_parts[5][8:12], 'little') ^ random.randint(0, 0xFFFFFFFF)
        ]
    
    if xor_results != [0xFBFF4501, 825199122, 0xFEEF2AA6]:
        return False
    ```
    
* Tiếp tục phân tích đến `part[2]` ta sẽ dử dụng brute force để tìm ra giá trị của `part[2]` .
    
    ```python
    import hashlib
    import random
    
    def check(flag):
        print("check")
        hash_value = hashlib.sha256(flag.encode()).hexdigest()
        if hash_value != '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a':
            return False
        print("done")
        return True
    
    for i in range (256):
        if check(str(i)):
            print(i)
            break
    ```
    
* Vậy giá trị tìm được của `part[2] = 4.` Tiếp tục phân tích code thì nhận ra 1 điểm tại đây `random.seed(input_parts[2])` sẽ tạo ra việc khi ta gọi `random.seed()` với cùng một giá trị đầu vào, bộ sinh số ngẫu nhiên sẽ được thiết lập ở trạng thái ban đầu giống nhau. Điều này dẫn đến việc các số ngẫu nhiên được sinh ra sau đó sẽ giống nhau giữa các lần chạy chương trình, miễn là bạn sử dụng cùng một giá trị seed.
    
* Cùng xử lý nó với `part[3]`.
    
    ```python
    import hashlib
    import itertools
    import random
    
    sample = [49, 89, 102, 109, 108, 52]
    perm = list(itertools.permutations (sample)) 
    
    for i in perm:
        random.seed (b'4')
        temp = list(i)
        random.shuffle (temp)
        if (temp == sample):
            res = list(map(chr, list(i)))
            print(''.join(res))
    ```
    
* Phần `part[4]` chỉ kiểm tra đơn giản ta được `part[4] = '0f'` .
    
* Lúc này Flag của chúng ta trở thành
    
    `amateursCTF{PY7h0ns_ar3_4_f4m1lY_0f_xxxxxxxxxxx_xxxxxx}`
    
* Gần hoàn thành rồi cùng đến với `part[5]` ở đây nhìn có vẻ khoai vì xor random các số từ 0 đến 0xFFFFFFFF nhưng ta đã có seed tại 4. Đây cũng tương tự như `part[3]` ta sẽ sử dụng `seed(4)` để hoàn ra được chuỗi cần tìm.
    
    ```python
    import hashlib
    import itertools
    import random
    
    sample = [49, 89, 102, 109, 108, 52]
    xor_res = [0xFBFF4501, 825199122, 0xFEEF2AA6]
    input = [b"", b"", b""]
    random.seed(b'4')
    random.shuffle(sample)
    input[0] = (random.randint(0, 0xFFFFFFFF) ^ xor_res[0]).to_bytes(4, 'little')
    input[1] = (random.randint(0, 0xFFFFFFFF) ^ xor_res[1]).to_bytes(4, 'little')
    input[2] = (random.randint(0, 0xFFFFFFFF) ^ xor_res[2]).to_bytes(4, 'little')
    x = b''.join(input).decode('utf-8')
    print('part 5 -', x)
    ```
    
* Sau khi chạy code thì ta được chuỗi `N0Nv3nom0us` .
    
* Tiếp tục với phần 6 còn lại.
    
    ```python
    c = 0
    for i in input_parts[6]:
        c *= 128
        c += i
    
    if hex(c) != '0x29ee69af2f3':
        return False
    
    return True
    ```
    
* Ta được chuỗi cuối cùng là `Sn4kes` sau khi tìm `part[6]` bằng đoạn code dưới đây.
    
    ```python
    c = 0x29ee69af2f3
    s = []
    while c > 0:
        s.insert(0, c % 128)
        c //= 128
    a = ""
    for i in s:
        a += chr(i)
    
    print(a)
    ```
    

### Result

* Vậy ta đã hoàn thành được flag của bài reverse .pyc này
    
    `amateursCTF{PY7h0ns_ar3_4_f4m1lY_0f_N0Nv3nom0us_Sn4kes}` .
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1690534041769/862e1ef8-8a30-4edd-8ac9-713aa455fa86.png align="center")
