---
# System prepended metadata

title: Crackme writeup

---

# Crackme writeup 

Задание выглядит следующим образом и является приложением windows forms (ну или wpf), написанным на c#.

![](https://i.imgur.com/TczX6FC.png)

Заметим, что весь проект скомпилирован в один исполняемый файл.

Откроем его в любом изветном декомпиляторе (я использовал dotpeek).

Заметим несколько файлов:

![](https://i.imgur.com/aULkHpt.png)

`MainWindow.cs` содержит обработчики элементов управления формы, и несколько проверочных и вспомогательных функций: `ConvertHexStringToByteArray`, `OnlyHexInString`. Но в целом - ничего интересного.

Введенная почта проверяется на наличие "@", код должен содержать только hex-символы. Если введенные данные корректны, они проверяются в `Dllloader.CheckSerial(text, byteArray)`.

Заметим, что перед этим вызывается Dllloader.LoadDll().

Нужная dll'ка декодируется из base64:
`public byte[] GetDLL() => Convert.FromBase64String(Resources.base64);`

Затем выделяем под нее память и кладем по адресу указателя:
```
IntPtr num = Marshal.AllocHGlobal(dll.Length);
Marshal.Copy(dll, 0, num, dll.Length);
```

Затем, в `LoadDll()` присваиваем в делегат типа:

```
IntPtr ptr = this.LoadFromMem();
this.Func = (Loader.d713235dbd24f7d3) Marshal.GetDelegateForFunctionPointer(ptr, typeof (Loader.d713235dbd24f7d3));
```

Дальше, в `CheckSerial(string email, byte[] serial`, где проверяется введенная почта и код, мы сначала копируем их в память:

```
byte[] bytes = Encoding.UTF8.GetBytes(email);
IntPtr num1 = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, num1, bytes.Length);
IntPtr num2 = Marshal.AllocHGlobal(serial.Length);
Marshal.Copy(serial, 0, num2, serial.Length);
```
А затем вызываем делегат, передавая указатель на почту, длину почты, а также указатель на код.

`bool flag = this.Func(num1, email.Length, num2);`

Достанем dll-ку из base64:

```
>>> from base64 import b64decode
>>> open('kek.dll', 'wb').write(b64decode(open('CrackMe2018.Res.base64.txt', 'r').read()))
75264
```

Посмотрим на нее <s>ida</s> и декомпилируем нужную функцию `d713235dbd24f7d3`:
![](https://i.imgur.com/8Rp6tta.png)

Поменяем типы аргументов и переименуем переменные:

![](https://i.imgur.com/ftcI0Y2.png)

Перепишем на плюсы для того, чтобы понять, что вообще происходит: 

```
#include <iostream>
#include <string>
using namespace std;
#define __PAIR64__(high, low) (((uint64_t) (high) << 32) | (uint32_t)(low))
#define byte unsigned char

bool check(byte *mailPtr, int mailLength, byte *codePtr)
{
  byte *cur; // ecx
  int offset; // eax
  int ersk; // esi
  int kasp; // edi
  int offset1; // ebx
  unsigned int v8; // edi
  int v9; // kr00_4

  cur = codePtr;
  offset = 0;
  ersk = 0x4552534B; // ERSK
  kasp = 0x4B415350; // KASP 
  
  printf("vars - %08x %08x\n", *(uint32_t *)cur, *((uint32_t *)cur + 1));
  printf("code - %08x %08x\n\n", ersk, kasp);
  
  while ( codePtr[offset] )
  {
    if ( ++offset >= 10 )
    {
      offset1 = 0;
      if ( mailLength > 0 )
      {
        do
        {
          v9 = mailPtr[offset1] + ersk;
          v8 = (mailPtr[offset1++] + __PAIR64__(kasp, ersk)) >> 32;
          kasp = __PAIR64__(v8, v9) >> 28;
          ersk = 16 * v9;
        }
        while ( offset1 < mailLength );
        cur = codePtr;
      }
      *cur ^= cur[9];
      
      printf("vars - %08x %08x\n", *(uint32_t *)cur, *((uint32_t *)cur + 1));
      printf("code - %08x %08x\n", ersk, kasp);
      return *(uint32_t *)cur == ersk && *((uint32_t *)cur + 1) == kasp;
    }
  }
  return 0;
}
int main()
{
    byte mail[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    byte code[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10};
    int mailLength = 10;
    
    cout << check(mail, mailLength, code);

}
```

Заметим, что переменные `kasp` и `ersk` как-либо меняются в зависимости от почты. Первый байт кода ксорится с последним. Затем, первые 4 байта кода сравниваются с `ersk`, а последние - с `kasp`. Заблекбоксим алгоритм, подобрав код для почты `kek@kek.kek`.

Переменные превратятся в:
```
ersk = 1be4a5d0 
kasp = 253bcbf7
```

Подберем последний байт ключа так, чтобы при ксоре с первым он давал d4.

Получим код - `    byte code[10] = {0xb0, 0xa5, 0xe4, 0x1b, 0xf7, 0xcb, 0x3b, 0x25, 0x09, 0x60};`

Ответ для почты: `kek@kek.com` - `b0a5e41bf7cb3b250960`

![](https://i.imgur.com/grJTqMQ.png)
