JuncoJet 发表于 2024-6-13 08:35

来自Keymaker中的cm例子

最近是技术退步了还是技术退步了,竟分析了一天毫无头绪{:1_906:}
好在是ASM编写的,正在努力暴力分析
拿上来网友试试

JuncoJet 发表于 2024-6-13 09:17

本帖最后由 JuncoJet 于 2024-6-13 09:20 编辑

研究出来了
因为是ASM写的CM所以代码全是汇编指令
没有什么特征,而且指令用的比较冷门
比如求字符串长度,还有比较字符串的代码

zunmx 发表于 2024-6-17 17:11

暴力破解:

爱飞的猫 发表于 2024-6-30 00:15

`401A46` 是主要窗口事件处理函数,其中:

处理 `WM_INITDIALOG` 时,为机器码控件注册了个自己的事件处理函数:

```c
    gControlHwnd = GetDlgItem(hWnd, 101);       // gControlHwnd = 机器码控件句柄
    unknown = j_SetWindowLongA(gControlHwnd, GWL_WNDPROC, (LONG)sub_401EBA);
    j_SetWindowLongA(gControlHwnd, GWL_USERDATA, unknown);
```

当处理的窗口事件为 `WM_COMMAND` (按下按钮)时,利用 `PostMessageA` 通知机器码控件的事件处理函数进行序列号验证处理:

```c
      if ( lParam )
      {
      if ( lParam >= 0xB )
          PostMessageA(gControlHwnd, 1123u, 1u, lParam); // 第一次进入
      else
          MessageBoxA(hWnd, "错误的注册码!请确认你输入的大小写是否正确。", 0, 0x10u);
      }
      else
      {
      MessageBoxA(hWnd, "注册成功!谢谢你的注册。", "完成", 0);
      }
```

(`lParam` 存储按钮控件句柄,永不为 `0`)

继续到 `401EBA` 分析 `1123` 号事件即可:

```c
      SendMessageA(gCodeFieldHandle, WM_GETTEXT, 100u, (LPARAM)code);
      SendMessageA(hWnd_machine_code, WM_GETTEXT, 260u, (LPARAM)machine_code);
      b64_decode(code, decoded);
      len = strlen(machine_code) + 1;
      v7 = machine_code;
      v8 = decoded;
      do
      {
          if ( !len )
            break;
          v9 = *v7++ == *(_BYTE *)v8;
          v8 = (int *)((char *)v8 + 1);
          --len;
      }
      while ( v9 );
      PostMessageA(gMainWndHandle, WM_COMMAND, 1u, len);
```

`004023B8` 看起来就是个标准的 `base64` 解密过程,然后将机器码与序列号解码后的内容进行比对。

相同则 `len = 0`,否则 `len = 其他值`。

---

Python 做的注册机:

```py
import base64

def keygen(machine_code: str) -> str:
return base64.b64encode(machine_code.encode()).decode().rstrip('=')

# machine_code: 123456789
# serial      : MTIzNDU2Nzg5
```

页: [1]
查看完整版本: 来自Keymaker中的cm例子