Решение ksydfius - The XOR Algorithm II

Сложность: 2 – Needs a little brain (or luck)
Платформа: Windows
Язык: Assembler
Дано: The XOR Algorithm II

Ага, моя первая задачка The XOR Algorithm была слишком легкой
Но, возможно, потому, что вы знали индекс ключа, который XORится с символом открытого текста?

Во всяком случае, я внес в алгоритм небольшое изменение :)

И будет ли от этого алгоритм более криптостойкий?
:)

Решение (авторы ThePoolGuy, RandolphCarter, ivvei)
опубликовано ThePoolGuy (02.10.2012), RandolphCarter (10.10.2012), ivvei (02.11.2012) – только решение на Perl

Этот crackme является продолжением первого – The XOR Algorithm. Естественно, есть кое-что новенькое.

Итак, у нас в наличии есть открытый текст (plaintext) по адресу 00403000, шифротекст (ciphertext) по адресу 004030F1. Используемый метод шифрования тот же - операция XOR. Нам нужно – найти ключ, с помощью которого преобразуем открытый текст в зашифрованный.
Логика crackme:

  1. Ждем от пользователя ввода ключа
  2. Шифруем открытый текст.
  3. Сравниваем полученный шифротекст с заданным в программе. Если шифротексты совпадают, то, используя тот же ключ, расшифровываем и показываем goodboy-сообщение.

Алгоритм шифрования (функция 0040106E):

image00.jpg

Красным цветом выделены изменения, добавленные в алгоритм этого crackme по сравнению с The XOR Algorithm.
Summa(k) – это сумма всех символов (их кодов), составляющих ключ. Нюанс в том, что ключ нам неизвестен, значит, и сумма его символов тоже неизвестна. Но нам поможет тот факт, что используется не вся сумма, а ее остаток от деления по модулю 32 (понятно, что dl – индекс ключа и он не должен быть больше его длины - 32). Вывод: нам достаточно проверить начальные значения dl от 0 до 31 (0x1F). Т.е. берем, например, dl = 0. И находим по обратному алгоритму символы ключа. Конечно, добавим условие: если на текущей позиции ключа уже есть символ и он не совпадает с найденным, то прерываем цикл нахождения ключа и переходим к следующему значению dl.

Код на Python:

# -*- coding: cp1251 -*-
def findkey(mysum, ciphertext, plaintext):
    key = [0]*32
    dl = mysum
    for i in range(len(plaintext)):
        k_char = ord(plaintext[i]) ^ (ciphertext[i] - dl)
        # Добавляем условие:
        # если уже в найденной позиции ключа есть символ, то сравниваем его с
        # k_char. Он должен совпадать, иначе отменяем поиск
        if (key[dl] <> 0) & (key[dl] <> k_char):
            return 0, key
        key[dl] = k_char
        dl = (ciphertext[i] + dl) % 32
    return 1, key
 
# pt - plaintext - открытый текст
pt = "We go about our daily lives understanding almost nothing of the world. \
Few of us spend much time wondering why nature is the way it is; where the \
cosmos came from;... why we remember the past and not the future; and why \
there is a universe."
 
# ct - ciphertext - шифротекст
ct = [
0x87, 0x2B, 0x73, 0x5A, 0x30, 0x20, 0x5F, 0x5F, 0x27, 0x39, 0x1E, 0x73, 0x2E, 0x64, 0x5D, 0x72,
0x29, 0x68, 0x76, 0x67, 0x19, 0x23, 0x42, 0x3C, 0x1E, 0x5C, 0x3D, 0x6D, 0x48, 0x78, 0x37, 0x37,
0x5B, 0x37, 0x47, 0x32, 0x52, 0x3A, 0x76, 0x69, 0x65, 0x64, 0x20, 0x2D, 0x54, 0x48, 0x3D, 0x39,
0x60, 0x2E, 0x52, 0x34, 0x3B, 0x6A, 0x71, 0x29, 0x8D, 0x2D, 0x5A, 0x6D, 0x47, 0x2B, 0x41, 0x6D,
0x4A, 0x38, 0x24, 0x6D, 0x29, 0x66, 0x72, 0x07, 0x5E, 0x6B, 0x20, 0x5D, 0x57, 0x24, 0x1B, 0x45,
0x68, 0x71, 0x60, 0x55, 0x37, 0x55, 0x70, 0x6E, 0x3A, 0x4C, 0x4F, 0x64, 0x35, 0x29, 0x33, 0x49,
0x73, 0x6A, 0x5D, 0x5F, 0x37, 0x37, 0x5B, 0x1D, 0x6F, 0x57, 0x60, 0x35, 0x61, 0x19, 0x23, 0x44,
0x31, 0x39, 0x33, 0x3B, 0x5C, 0x70, 0x6A, 0x5C, 0x60, 0x34, 0x3B, 0x5E, 0x14, 0x36, 0x60, 0x68,
0x76, 0x60, 0x65, 0x31, 0x2B, 0x23, 0x24, 0x64, 0x36, 0x59, 0x2B, 0x25, 0x23, 0x77, 0x65, 0x2E,
0x59, 0x7E, 0x4C, 0x25, 0x6A, 0x33, 0x43, 0x6A, 0x76, 0x5A, 0x62, 0x64, 0x54, 0x10, 0x69, 0x5B,
0x23, 0x2B, 0x7D, 0x6F, 0x1B, 0x84, 0x72, 0x38, 0x28, 0x46, 0x17, 0x28, 0x59, 0x7E, 0x5B, 0x3B,
0x6E, 0x2A, 0x41, 0x4B, 0x2E, 0x56, 0x09, 0x46, 0x61, 0x49, 0x73, 0x67, 0x58, 0x67, 0x47, 0x73,
0x58, 0x3C, 0x4D, 0x23, 0x44, 0x27, 0x38, 0x19, 0x6B, 0x77, 0x2B, 0x73, 0x59, 0x38, 0x2A, 0x65,
0x65, 0x50, 0x70, 0x8D, 0x1F, 0x34, 0x51, 0x0D, 0x5E, 0x6B, 0x5A, 0x73, 0x39, 0x28, 0x2A, 0x40,
0x49, 0x73, 0x50, 0x24, 0x09, 0x33, 0x71, 0x4E, 0x22, 0x2F, 0x69, 0x64, 0x25, 0x31, 0x6C, 0x62
]
 
# Ищем ключ
key = []
for i in range(32):
    ans,key = findkey(i,ct, pt)
    # Еще одна проверка:
    # сумма всех символов ключа (используем для этого reduce()-функцию)
    # по модулю 32 должна быть равна i (или, по нашему алгоритму, dl )
    if ans & (reduce(lambda a,b: a+b, key) % 32 == i):
        print("Summa(Key) % 32 = " + str(i))
        break
 
# Переводим байты в символы
szkey = "".join([chr(c) for c in key])
 
print("Key = "+szkey)


Key = A(U*SYGF(GH9(*5y9][@%}+)78y3htxa
Запускаем программу, вводим ключ, наблюдаем результат:

image01.jpg
Пока не указано иное, содержимое этой страницы распространяется по лицензии Creative Commons Attribution-ShareAlike 3.0 License