Решение mikkchl - FlamingPoop

Сложность: 1 - Very easy, for newbies
Платформа: Windows
Язык: .NET
Дано: FlamingPoop

My very first crack me. It's written in vb.net.
This is also my first vb.net program.
Virus scan: www.virustotal.com/file/4b90afe7…/analysis/ (0/43)
Just to proof that it's possible, have i already made a keygen to my program.
Enjoy!

Решение (автор draww)
опубликовано 02.07.2012

Инструменты: SAE (SimpleAssemblyExplorer)

1. Анализ

.NET программы удобно смотреть в SAE. Делаем простейшие шаги. Запускаем наш инструмент SimpleAssemblyExplorer, затем в «Проводнике» (левая панель) находим папку, где лежит crackme-задачка «register.exe» (правая панель), двойной клик по ней – для начала анализа.

image00.jpg

Ищем точку входа программы (Go to Entry Point).

image01.jpg

В точке входа (процедура Main) просто стартует приложение (MyProject.Application.Run(Args)). При этом отрабатывается событие OnCreateMainForm. Это событие позволяет разработчику создавать код, который настраивает экран-заставку и главную форму. Как видим, главная форма здесь Form3.

image02.jpg

Наблюдательный читатель увидит, что есть Form1 и Form2. Скажем сразу, это, видимо, эксперименты автора crackme. Вся логика задачки в Form3. В ней нас интересует только обработка нажатия кнопки Button1_Click. Дальнейшее обсуждение касается только этой процедуры.

image03.jpg

Первое условие
this.TextBox1.TextLength == 25
проверяет, что длина введенного ключа должна быть строго 25 символов. Если условие выполняется, то весь ключ разбивается на 25 частей (т.е. по одному символу), т.е. 25 раз вызываем функцию Substring(). После этого, 1-й символ нашего ключа сравнивается с четырьмя предопределенными значениями. Получаем аналог условия ветвления (switch).

switch (text) //1-й символ нашего ключа
{
  case "X":
      (таблица подстановки "X")
      break;
 
  case "Q":
      (таблица подстановки "Q")
      break;
 
  case "$":
      (таблица подстановки "$")
      break;
 
  case "|":
      (таблица подстановки "|")
      break;
 
  default:
      break;
}


Итак, наш ключ должен начинаться или на X, или на Q, или на $, или на |. Если не так, то получим badboy-сообщение. Дальше ключ расшифровывается через обыкновенную таблицу подстановок или замен (стандартная функция Replace()).
case "X":         case "Q":     case "$":     case "|":
«W» => «1»        «H» => «1»    «M» => «1»    «E» => «1»
«X» => «2»        «L» => «2»    «S» => «2»    «D» => «2»
«Y» => «3»        «T» => «3»    «C» => «3»    «J» => «3»
«U» => «4»        «Q» => «4»    «K» => «4»    «I» => «4»
«&» => «5»        «)» => «5»    «£» => «5»    «^» => «5»
«?» => «6»        «(» => «6»    «$» => «6»    «’» => «6»
«=» => «7»        «/» => «7»    «]» => «7»    «´» => «7»
«B» => «8»        «*» => «8»    «[» => «8»    «|» => «8»
«>» => «9»        «_» => «9»    «-» => «9»    «+» => «9»


Как видим, замена символов кодировки на цифры от 1 до 9. А где же «0»? А «0» можно передать «как есть», он отсутствует в табличке замен, значит, его изменения не коснутся.
Итак, у нас каждый символ ключа (всего их 25) – это цифра от «0» до «9». Пронумеруем их:1-й, 2-й, 3-й… 25-й. А теперь финальная проверка, простая математика с равенством на фиксированные значения:

(1-й + 5) + (7-й * 2) = 25
(2-й * 3) + 5-й + 7 = 34
(3-й * 5) + 9-й + 2 = 31
(4-й * 2) + 6-й + 2 = 20
(8-й * 4) + 10-й + 2 = 28
(11-й + 5) + (18-й * 3) = 34
(12-й * 2) + 15-й + 2 = 19
(13-й * 3) + 20-й + 4 = 27
(14-й * 2) + 19-й + 4 = 26
(16-й * 3) + 17-й + 4 = 30
(21-й * 3) + 24-й + 3 = 27
(22-й * 4) + 23-й + 1 = 28
25-й = 5

Проверки состоят только из умножения (*) и сложения (+). После того, как мы упростим уравнения, мы получим тринадцать условий. Выполнив их, мы сформируем правильный ключ.

Упрощенное уравнение    Условие                   Результат
7-й  * 2 + 1-й  = 20    (7-й  > 5)                7-й равен одному из значений 6,7,8,9 (num7)
2-й  * 3 + 5-й  = 27    (2-й  > 5)                2-й  равен одному из значений 6,7,8,9 (num2)
3-й  * 5 + 9-й  = 29    (3-й  > 3 & 3-й < 6)      3-й  равен одному из значений 4,5 (num3)
4-й  * 2 + 6-й  = 18    (4-й  > 4)                4-й  равен одному из значений 5,6,7,8,9 (num4)
8-й  * 4 + 10-й = 26    (8-й  > 4 & 8-й < 7)      8-й  равен одному из значений 5,6 (num8)
18-й * 3 + 11-й = 29    (18-й > 6)                18-й равен одному из значений 7,8,9 (num18)
12-й * 2 + 15-й = 17    (12-й > 3 & 12-й < 9)     12-й равен одному из значений 4,5,6,7,8 (num12)
13-й * 3 + 20-й = 23    (13-й > 4 & 13-й < 8)     13-й равен одному из значений 5,6,7 (num13)
14-й * 2 + 19-й = 22    (14-й > 6)                14-й равен одному из значений 7,8,9 (num14)
16-й * 3 + 17-й = 26    (16-й > 5 & 16-й < 9)     16-й равен одному из значений 6,7,8 (num16)
21-й * 3 + 24-й = 24    (21-й > 4 & 21-й < 9)     21-й равен одному из значений 5,6,7,8 (num21)
22-й * 4 + 23-й = 27    (22-й > 4 & 22-й < 7)     22-й равен одному из значений 5,6 (num22)
25-й                     = 5                      25-й равен 5 (num25)


Что означают условия? А то, что если случайно выбрать значение 7-й цифры (num7) от 6 до 9, то можно вычислить значение 1-й цифры (num1): 20 – 7-й * 2; задаем значение 2-й цифры (тоже от 6 до 9), вычисляем 5-ю цифру: 27- 2-й * 3. И т.д.
Зная условия, можно перейти к созданию кейгена.

2. Кейген
  • Задаем начальные значения для позиций цифр, у каждой свой диапазон значений: num7, num2, num3, num4, num8, num18, num12, num13, num14, num16, num21, num22, num25.
  • Зная num7, вычисляем num1; из num2 получаем num5; из num3 получаем num9 и т.д. (см. выше столбец «Упрощенное уравнение»)
  • А теперь процесс кодирования. Цифры в символы. Таблица перестановок выбирается на основании 1-го символа. Это num1. Возможные его значения: 2, 4, 6, 8. Соответствие здесь однозначное. Для «2» таблица «X», для «4» = таблица «Q», для «6» = таблица «$»,для «8» = таблица «|». При замене обращаем внимание, что в табличках есть два unicode-символа: «£» = \u00A3 и «´» = \u00B4.
# -*- coding: cp1251 -*-
import random
 
# Создаем таблицы замен
t1 = ["0","W","X","Y","U","&","?","=","B",">"]
t2 = ["0","H","L","T","Q",")","(","/","*","_"]
t3 = ["0","M","S","C","K",u'\u00A3',"$","]","[","-"]
t4 = ["0","E","D","J","I","^","'",u'\u00B4',"|","+"]
 
# Набор соответствий. "2" - t1, "4" - t2
to_set = [(t1, 2), (t2, 4), (t3, 6), (t4, 8)]
 
# Создаем предопределенные переменные
num2  = random.randint(6,9)
num3  = random.randint(4,5)
num4  = random.randint(5,9)
num7  = random.randint(6,9)
num8  = random.randint(5,6)
num12 = random.randint(4,8)
num13 = random.randint(5,7)
num14 = random.randint(7,9)
num16 = random.randint(6,8)
num18 = random.randint(7,9)
num21 = random.randint(5,8)
num22 = random.randint(5,6)
num25 = 5
 
# Вычисляем остальные переменные
num1 = 20 - num7 * 2
num5 = 27 - num2 * 3
num9 = 29 - num3 * 5
num6 = 18 - num4 * 2
num10 = 26 - num8 * 4
num11 = 29 - num18 * 3
num15 = 17 - num12 * 2
num20 = 23 - num13 * 3
num19 = 22 - num14 * 2
num17 = 26 - num16 * 3
num24 = 24 - num21 * 3
num23 = 27 - num22 * 4
 
# Собираем ключ. Пока в виде числа.
temp = ""
temp = str(num1)+str(num2)+str(num3)+str(num4)+str(num5)+str(num6)+str(num7)
temp += str(num8)+str(num9)+str(num10)+str(num11)+str(num12)+str(num13)+str(num14)
temp += str(num15)+str(num16)+str(num17)+str(num18)+str(num19)+str(num20)+str(num21)
temp += str(num22)+str(num23)+str(num24)+str(num25)
 
# Смотрим, какой у нас 1-й символ. Выбираем таблицу замен.
t_list = []
to_set_list = list(to_set)
for i in range(4):
    if to_set_list[i][1] == num1:
        t_list = to_set_list[i][0]
 
# Кодировка цифр в символы
serial = ""
for i in xrange(25):
    serial += t_list[int(temp[i])]
 
# Выводим результат
print ("[+]Serial = "+unicode(serial))


Примеры:
[+]Serial = X?U=>U>?>XX?&B&?B>?B??Y?&
[+]Serial = |+I^0|''+DD´´´J'|+|D'^´'^
[+]Serial = $-K[0S]£-$S]$[C$[-$£[£]0£
[+]Serial = Q/)*(L*)Q(*/(*T(*/()/)/T)

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