Если это домашнее задание, то оно довольно сложное. (Хотя, возможно, я упустил простой подход.)
Давайте сосредоточимся на влиянии этого кода на память . Для простоты я предполагаю, что вас не интересует влияние этого кода на регистры , хотя я не могу быть уверен, увидев код, вызывающий эту функцию.
encryptL:
push eax
... ; ignoring this code because its effect on eax is undone by the following pop
pop eax
... ; code not affecting eax
movzx ecx, [eax]
... ; code not affecting eax
mov [eax], cl
ret
Итак, адрес идет (eax
). Байт по этому адресу помещается в cl
, а после некоторых преобразований cl
возвращается по тому же адресу.
Нам нужно выяснить, что это за преобразования, и инвертировать их.
ror cl, 1
xor cl, 0x96
push ecx
... ; ignoring this code because its effect on ecx is undone by the following pop
pop ecx
xor ecx, edx
Таким образом, поворот и два xors применяются к cl
.
Xor - это инволюция , поэтому нам не нужно менять эти две инструкции.
Обратное значение rol
, конечно, ror
, хотя это не совсем так. Эффект на флаге переноса не может быть инвертирован, но в этом случае этот эффект игнорируется, поэтому мы хороши.
Но как насчет всего кода, который мы игнорировали? При внимательном рассмотрении вы заметите, что он рассчитывает только значение edx
, которое используется в xor ecx,edx
.
К сожалению, исходное (незашифрованное) значение [eax]
участвует в этом расчете.
При дешифровании исходное значение становится окончательным, то есть результатом xor ecx,edx
.
Кажется, у нас проблемы с яйцом и курицей. Как выполнить расчет, когда он зависит от результата того же расчета?
Должно быть ясно, что влияние [eax]
на вычисление edx
, является либо 1 из 8 возможных случаев, из-за этого утверждения:
and cl, 0x7
Это означает, что мы можем использовать цикл, чтобы опробовать все различные возможности, пока не найдем тот, в котором результат вычисления совпадает со значением, найденным в [eax]
.
Этот цикл будет очень похож на этот цикл в шифраторе:
X:
add dl, 2
sub cl, 1
jg X
Однако условие выхода из цикла будет другим.
mov bl,0 ; using bl as a loop counter (similar to cl in original loop)
X:
inc bl
add dl,2 ; same as in the original loop
mov cl,[eax] ; fetch encrypted byte from memory
xor ecx,edx ; try transforming cl with the current value of dl
xor ebx,ecx ; compare cl with the loop counter (bl)
and bl,7 ; only compare the 3 least significant bits
jg X ; if not zero, try again with the next possible value of dl
Поскольку xor
является коммутативным и ассоциативным, мы можем переписать этот код.
Вместо увеличения bl
до совпадения с cl
мы будем уменьшать cl
до тех пор, пока его (частично) преобразованное значение не станет равным нулю (по модулю 8).
mov cl,[eax] ; fetch encrypted byte from memory
X:
add dl,2 ; same as in the original loop
sub cl,1 ; same as in the original loop
push ecx
xor ecx,edx ; transform cl with the current value of dl
and cl,7 ; only consider the 3 least significant bits
pop ecx ; restore cl (without clobbering flags)
jg X ; if equal, then we found the right starting point
Что касается остальной части кода, он может оставаться как есть. В основном это начальная часть вычисления edx
, прежде чем [eax]
становится вовлеченным.
Вот полное решение:
encryptL:
push eax
xchg eax, ecx
neg al
inc eax
rol al, 1
rol al, 1
mov ebx, eax
pop eax
push ebx
pop edx
movzx ecx, [eax]
push ecx
X:
add dl,2
sub cl,1
push ecx
xor ecx,edx
and cl,7
pop ecx
jg X
pop ecx
xor ecx,edx
xor cl,0x96
rol cl,1
mov [eax],cl
ret
Отказ от ответственности: я не тестировал его, поэтому вполне вероятно, что он не будет работать. Я оставлю отладку до вас.