Memecahkan crackme dari Kaspersky Lab

Suatu hari, saluran yang berbeda di telegram mulai melemparkan tautan ke pembuat crack dari LK. Mereka yang berhasil menyelesaikan tugas akan diundang untuk wawancara! . Setelah pernyataan keras seperti itu, saya bertanya-tanya seberapa sulit sebaliknya. Bagaimana saya menyelesaikan tugas ini dapat dibaca di bawah potongan (banyak gambar).

Setelah tiba di rumah, saya kembali membaca tugas itu dengan hati-hati, mengunduh arsip dan mulai melihat apa yang ada di dalamnya. Dan di dalamnya ada:



Kita mulai x64dbg, buang setelah membongkar, lihat apa yang ada di dalamnya:





Kami mengambil nama file dari argumen baris perintah -> buka, baca -> mengenkripsi langkah pertama -> mengenkripsi langkah kedua -> menulis ke file baru.

Sederhana, saatnya untuk melihat enkripsi.

Mari kita mulai dengan stage1


Pada alamat 0x4033f4 ada fungsi yang saya sebut crypt_64bit_up (nanti Anda akan mengerti mengapa), itu dipanggil dari loop di suatu tempat di dalam stage1



Dan hasil dekompilasi agak bengkok



Pada awalnya saya mencoba untuk menulis ulang algoritma yang sama dengan python, membunuhnya selama beberapa jam dan ternyata sesuatu seperti ini (yang memang get_dword dan byteswap harus jelas dari namanya)

def _add(x1, x2): return (x1+x2) & 0xFFFFFFFF def get_buf_val(t, buffer): t_0 = t & 0xFF t_1 = (t >> 8) & 0xFF t_2 = (t >> 16) & 0xFF t_3 = (t >> 24) & 0xFF res = _add(get_dword(buffer, t_0 + 0x312), (get_dword(buffer, t_1 + 0x212) ^ _add(get_dword(buffer, t_2+0x112), get_dword(buffer, t_3+0x12)))) # print('Got buf val: 0x%X' % res) return res def crypt_64bit_up(initials, buffer): steps = [] steps.append(get_dword(buffer, 0) ^ byteswap(initials[0])) # = z steps.append(get_buf_val(steps[-1], buffer) ^ byteswap(initials[1]) ^ get_dword(buffer, 1)) for i in range(2, 17): steps.append(get_buf_val(steps[-1], buffer) ^ get_dword(buffer, i) ^ steps[i-2]) res_0 = steps[15] ^ get_dword(buffer, 17) res_1 = steps[16] print('Res[0]=0x%X, res[1]=0x%X' % (res_0, res_1)) 

Tapi kemudian saya memutuskan untuk memperhatikan konstanta 0x12, 0x112, 0x212, 0x312 (tanpa hex 18, 274, 536 ... tidak sangat mirip dengan sesuatu yang tidak biasa). Kami mencoba untuk google mereka dan menemukan seluruh repositori (petunjuk: NTR) dengan penerapan fungsi enkripsi dan dekripsi , ini adalah keberuntungan. Kami mencoba mengenkripsi file uji dengan konten acak di program asli, membuangnya, dan mengenkripsi file yang sama dengan skrip kecil, semuanya harus berfungsi dan hasilnya harus sama. Setelah itu, kami mencoba mendekripsi (saya memutuskan untuk tidak memerinci dan hanya menyalin-tempel fungsi dekripsi dari sumber)

 def crypt_64bit_down(initials, keybuf): x = initials[0] y = initials[1] for i in range(0x11, 1, -1): z = get_dword(keybuf, i) ^ x x = get_buf_val(z, keybuf) x = y ^ x y = z res_0 = x ^ get_dword(keybuf, 0x01) # x - step[i], y - step[i-1] res_1 = y ^ get_dword(keybuf, 0x0) return (res_1, res_0) def stage1_unpack(packed_data, state): res = bytearray() for i in range(0, len(packed_data), 8): ciphered = struct.unpack('>II', packed_data[i:i+8]) res += struct.pack('>II', *crypt_64bit_down(ciphered, state)) return res 

Catatan penting: kunci dalam repositori berbeda dari kunci dalam program (yang cukup logis). Oleh karena itu, setelah kunci diinisialisasi, saya hanya membuangnya ke file, ini adalah buffer / keybuf

Kami lolos ke bagian kedua


Semuanya jauh lebih sederhana di sini: pertama, array char unik dibuat dengan ukuran 0x55 byte dalam kisaran (33, 118) (karakter yang dapat dicetak), kemudian nilai 32-bit dikemas ke dalam 5 karakter yang dapat dicetak dari array yang dibuat sebelumnya.





Karena tidak ada keacakan ketika membuat array yang disebutkan di atas, setiap kali program dimulai, array ini akan sama, kita membuangnya setelah inisialisasi dan kita dapat membongkar stage_2 dengan fungsi sederhana

 def stage2_unpack(packed_data, state): # checked! res = bytearray() for j in range(0, len(packed_data), 5): mapped = [state.index(packed_data[j+i]) for i in range(5)] res += struct.pack('>I', sum([mapped[4-i]*0x55**i for i in range(5)])) return res 

Kami melakukan sesuatu seperti ini:

 f = open('stage1.state.bin', 'rb') stage1 = f.read() f.close() f = open('stage2.state.bin', 'rb') stage2 = f.read() f.close() f = open('rprotected.dat', 'rb') packed = f.read() f.close() unpacked_from_2 = stage2_unpack(packed, stage2) f = open('unpacked_from_2', 'wb') f.write(unpacked_from_2) f.close() unpacked_from_1 = stage1_unpack(unpacked_from_2, stage1) f = open('unpacked_from_1', 'wb') f.write(unpacked_from_1) f.close() 

Dan kami mendapatkan hasilnya

Source: https://habr.com/ru/post/id431690/


All Articles