x64dbg-算法分析二.md
9unk Lv5

目标程序

程序下载:Splish

解压密码:9unk

任务目标:分析 Name/Serial 部分的算法,并写出注册机程序。

观察程序

32.jpg

算法分析

加载 Splish,断在入口点。

1.jpg

查看程序使用的 API,并对 GetWindowTextA 设置断点

2.jpg

继续运行程序

3.jpg

执行到返回,此时数据已经存到缓冲区。

4.jpg

我们继续跟踪到数据窗口

5.jpg

对数据设置内存访问断点

6.jpg

继续运行程序,此时停在了另一个 GetWindowTextA API 处。

7.jpg

我们 “F9” 继续运行,然后执行返回,可以看到缓冲区存储的是 Name

8.jpg

我们继续单步步过,此时程序在比较和跳转指令处

9.jpg

我们双击跳转指令,看看是跳转到哪里。

10.jpg

可以看到此时程序跳转到了 MessageBox 处,消息是 “please enter your name”,由此可以断定上面的比较跳转是在判断 name 是否为空。

我们继续执行程序,可以看到上面这段指令是在初始化寄存器,然后 esi 指向 “9unk”、edi 指向空值、ecx 存储 0xA

11.jpg

我们开始分析下面的循环部分的指令,第一个指令是把 name 的第一个字节存储到 eax 中

12.jpg

1
cdq     // 把 edx 扩展为 eax 的最高位,也就是说 eax 由 32 位扩展到了 64 位

现在 eax 的值是 edx + eax = 00000000 00000039

13.jpg

1
idiv ecx    // eax/ecx 商存储在 eax 中,余数存储在 edx 中

现在商是 0x5,余数是 0x7

14.jpg

1
2
3
4
xor edx, ebx    // edx 异或 ebx
add edx, 0x2 // edx + 0x2
cmp dl,A // dl - 0xA
jl 0x00401646 // 有符号数跳转,小于就跳转

15.jpg

16.jpg

1
mov byte ptr ds:[edi+ebx*1], dl         // dl 存到 [edi + ebx * 1]

17.jpg

1
2
3
inc ebx                                 // ebx + 1
cmp ebx, dword ptr ds:[0x00403463] // ebx - 4
jne 0x00401632 // 不等于零就跳转

这一段主要就是判断循环是否结束

18.jpg

19.jpg

循环结束后,看一下 name 计算后的值是 “09080406”

20.jpg

总结 name 计算步骤:(((name%0xA) xor ebx) + 0x2)-0xA;ebx 每次循环加 1;如果 name > 0xA,name = name - 0xA

我们继续向下执行,可以看到下面是计算 password 的循环

21.jpg

1
2
3
movsx eax, byte ptr ds:[esi+ebx*1]
cdq
mov byte ptr ds:[edi+ebx*1], dl

22.jpg

可以看到 password 计算部分就是:password % A

1
2
3
inc ebx
cmp ebx, dword ptr ds:[0x00403467]
jne 0x00401669

判断循环是否结束

23.jpg

最后看一下循环结束的结果是:”090001020304”

24.jpg

总结 password 计算步骤:password % 0xA

我们循环结束后,后面是 jmp 指令,双击查看跳转的位置。可以看到这又是一个循环,这段循环应该是在计算比较正确的 serial 。

25.jpg

我们继续步过运行程序,首先 password 的计算结果存到 esi 中,name 的计算结果存到 edi 中。

26.jpg

27.jpg

dword 值得是 2 个字,也就是 4 个字节。也就是说 password 的计算结果实际上是获取的 “09000102” 。现在比较的值应该是 name:”09080406” 和 password:”09000102”

1
2
cmp ebx, dword ptr ds:[0x00403463]
je 0x004016CD

正常循环结束,就跳出循环,弹出正确信息

28.jpg

1
2
3
4
movsx eax, byte ptr ds:[edi+ebx*1]      // 把 password 传到 eax
movsx ecx, byte ptr ds:[esi+ebx*1] // 把 name 传到 ecx
cmp eax, ecx // 比较 eax 和 ecx
jne 0x004016E2 // 不相等就跳转

第一次循环两个值相等

29.jpg

第二次循环值就不相等了

30.jpg

现在已经知道了计算的方法,我们先计算用户名 9unk 的 serial

1
2
3
4
31 % 0xA = 09      1
30 % 0xA = 08 0
36 % 0xA = 04 6
38 % 0xA = 06 8

31.jpg

注册机编写

  1. (((name%0xA) xor ebx) + 0x2)-0xA;ebx 每次循环加 1;如果 name > 0xA,name = name - 0xA
  2. password % 0xA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
程序名:Splish.c,此程序是 Splish.exe 的注册机
作者:9unk 日期:20201227
*/

#include <stdio.h>
#include <string.h>
#define size 21
int main()
{
char str[size];
int i=0,name=0;
int n=0;
int serial=0;


memset(str,0,sizeof(str));

printf("请输入你的用户名:");
scanf("%s",str);
printf("你的 serial 是:");

for(i=0;i<strlen(str);i++)
{
name=str[i]; // 字符串转换成十进制
name=name%0xA; // name 取余 0xA
name=name ^ i; // name xor i
name=name+0x2; // name + 0x2;最终得到 name 的计算结果
if(name>0xA)
{
name=name-0xA; //如果 name 大于 0xA ,name = name-0xA
}
for(n=48;n<=57;n++) // 这里使用 acsii 十进制来做循环
{
if(n%0xA==name) // 如果 serial % 0xA 等于 name,就输出 serial
{
printf("%c",n); // 将十进制转换成 ascii 码输出

}
}

}
printf("\n");

}

reference

关于汇编语言中cdq指令作用解惑

  • 本文标题:x64dbg-算法分析二.md
  • 本文作者:9unk
  • 创建时间:2020-12-29 01:48:12
  • 本文链接:https://9unkk.github.io/2020/12/29/x64dbg-suan-fa-fen-xi-er/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!