7 - anode

Phân tích ban đầu

  • Chạy thử chương trình chỉ hỏi flag và check flag

  • Kích thước file khá lớn khiến mình nghĩ có nên load vào IDA không vì có thể rất lâu IDA mới load xong

image

  • Có vẻ là chương trình có code js ở bên trong

  • Mở file bằng notepad++ thử:

image

  • Có vẻ phần check flag cũng là phần code js nằm ở cuối file

  • Searh gg mình tìm được một tool là nexe-decompile dùng để extract file js ra xem ở đây

  • Đọc code ta thấy đầu tiên nó check độ dài flag phải bằng 44

-Nhập thử:

image

  • Quan sát ta thấy đối với cái script bị extract thì bị lỗi còn cái file exe thì lại không (có lẽ là yếu tố code c của file exe ảnh hưởnng), suy nghĩ hoài mình ko biết cách pass làm sao nên mình quyết định làm việc trực tiếp trên file exe luôn, bỏ script js qua một bên.

Dump kết quả cuối

  • Đầu tiên mình sửa code lại để in ra kết quả cuối cùng:

image

  • Lưu ý: vừa thêm và xóa code phải đảm bảo sao cho số bytes xóa và số bytes thêm bằng nhau để đảm bảo kích thước cho file khi chạy không bị crash

  • Các trường hợp switch-case có các số random nên mình đoán khi chạy cùng input ở các thời điểm khác nhau sẽ cho ra kết quả khác nhau nhưng lại không như vậy:

image

Dump giá trị state

  • Ta cần giá trị state để biết thứ tự các case trong suốt quá trình chạy đến kết quả cuối

image

image

Dump giá trị random

  • Ta cần biết giá trị random ở một số case:

image

  • Tiếp tục patch để in ra bởi vì chúng ta biết nó không hề random, như vầy:

image

–> Có quá nhiều trường hợp có số random nên ta không thể patch bằng tay hết và còn phải lo về kích thước bytes nữa -> script:

f=open("anode_pat1.exe", 'rb').readlines()
f1=open("anode_pat1.exe", 'rb').read()
out=b""
patch=open("anode_pat2.exe", 'wb')

for li in f:
    
    if b'Math.floor(Math.random() * 256)' in li:
        add=b'console.log("-->"+Math.floor(Math.random() * 256));\n'
        add=add.rjust(len(li),b' ')
        f1=f1.replace(li, add)
    
patch.write(f1)

image

Dump if/else

  • Các case còn có 2 trường hợp if/else nên ta cần phải dump ra xem mỗi case nó theo nhánh nào

image

  • Thêm như vầy nếu mỗi case theo trường hợp if thì in ra c1 còn không in ra gì thì theo trường hợp else

  • Tương tự như trên rất khó để làm bằng tay

f=open("anode_pat1.exe", "rb").readlines()
f1=open("anode_pat1.exe", "rb").read()

case=open("case.exe", 'wb')

import re

for li in range(len(f)):
    if (re.findall(r"""case \d{3,}:\n""".encode(),f[li]) != []):
        if b'case 185078700' in f[li]:
            continue
        assert b"if" in f[li+1]
        if b'Math.floor(Math.random()' in f[li+2]:
            add=b'console.log("c1,  "+Math.floor(Math.random() * 256));\n'
            add=add.rjust(len(f[li+2]),b' ')

        else:
            add=b'console.log("c1");\n'
            add=add.rjust(len(f[li+2]),b' ')
        
        f1=f1.replace(f[li+2], add)
case.write(f1)

image

Kết hợp

  • Đến đây ta đã có hết dữ liệu ta cần, bây giờ chỉ việc build lại luồng thôi

  • Code build dựa trên điều kiện của mỗi trường hợp:

  • print_flow.py

  • Kết quả: flow.txt

Get flag

  • Đến đây thì đảo ngược thứ tự flow lại thôi

  • solve.py

image

8 - backdoor

(Phần deobfuscate không nhớ mình đem code vứt đi mà mình thì lười làm lại nên xin dời lại có gì viết sau :«)