Skip to main content

Command Palette

Search for a command to run...

Reverse Python Bytecode

Updated
12 min read
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.

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.

  • 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.

  • Đâ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.

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 .
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ì 😞.
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 được recommend nhiều nhất.

  • 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ũ.

  • Đến đây ta đã có file dumps.pyc => 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.

  • Đâ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.

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.

      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.

      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
    
  • 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.

      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}

      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] .

      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].

      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.

      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.

      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.

      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} .