1、Acid burn

1、Acid burn

简述:

难度:一颗星

操作系统: Windows(XP)[I386, 32 位, GUI]

链接程序: Turbo Linker(2.25*,Delphi)[GUI32]

编译器: Borland Delphi(3)[Standard]

语言: Object Pascal(Delphi)

准备工作

这里直接使用 die 进行查即可

image

发现无壳子,这时候就可以直接进行逆向了。

首先看一下该函数调用了那些库函数。

image

其实就这些基础函数,这里我们就先不理会了。

直接打开界面

我们会发现有两个。一个是序列号,一个是用户名+序列号

我们先整序列号的

序列号破解分析

直接拖入x32dbg,因为是32位程序

这里说一下一般破解的思路。其实就是直接将其运行起来。点击对应的功能查看是否弹窗,有弹窗基本就好办了。开始操作。

image

我们直接点击check 不管他输入的是什么

image

发现是这样的。

直接点暂停

image

然后堆栈回调

要注意关注 用户模块。系统模块无需理会

image

回一层。发现有调用messagebox。回两层便可以看到字符串了。

image

这里直接,在call 这里打一个断点。,重新走到这里

image

eax 和edx传参 内平栈 fastcall 通过jne跳转可以看出来,zf 标志位为0时不跳转。

eax 指向  [ebp-10]: "Enter the serial here !!!!!"
edx 指向  [ebp-C]:  "Hello Dude!"

保护现场
4039FC | 53                       | push ebx                            
4039FD | 56                       | push esi                            
4039FE | 57                       | push edi  

把两个参数分别赋值给 esi edi
4039FF | 89C6                     | mov esi,eax                         
403A01 | 89D7                     | mov edi,edx                         
403A03 | 39D0                     | cmp eax,edx                         
403A05 | 0F84 8F000000            | je acid burn.403A9A     
....
403A9A | 5F                       | pop edi                             
403A9B | 5E                       | pop esi                             
403A9C | 5B                       | pop ebx                             
403A9D | C3                       | ret   

这里开始分析这两行。。可以看出来。

当输入的字符串为Hello Dude! 时可以正确打印。

所以我们进行尝试一下

image

我们继续分析 Serial/Name

直接按照之前的方法跳转到关键点。

0042FAF | 8B55 F0           | mov edx,dword ptr ss:[ebp-10]      | [ebp-10]:"Enter your serial here !"
0042FAF | 8B45 F4           | mov eax,dword ptr ss:[ebp-C]       | [ebp-C]:"CW-4018-CRACKED"
0042FAF | E8 F93EFDFF       | call acid burn.4039FC              |
0042FB0 | 75 1A             | jne acid burn.42FB1F               |

即可以看到这里。这时候就可以知道是比较两个字符串的大小,找一下这个字符串是从哪里来的。其实多调试几次就可以发现,两边的 CW​ 和 CRACKED​ 都没有改变过。这里只是纯碰运气,并没有技术含量,下面开始做有技术含量的事情把。

这里定位关键函数的方法就不说了。上面也说了,一致回调,如何每个函数都调一下就知道了。

下面就开始逐行分析汇编逻辑了。

这几行都和我们的注册机没啥关系

0042F9A | 55                | push ebp                           |
0042F9A | 68 67FB4200       | push acid burn.42FB67              |
0042F9A | 64:FF30           | push dword ptr fs:[eax]            |
0042F9B | 64:8920           | mov dword ptr fs:[eax],esp         |
0042F9B | C705 50174300 290 | mov dword ptr ds:[431750],29       | 29:')'
0042F9B | 8D55 F0           | lea edx,dword ptr ss:[ebp-10]      | [ebp-10]:"112233"
0042F9C | 8B83 DC010000     | mov eax,dword ptr ds:[ebx+1DC]     | [ebx+1DC]:&"d稝"
0042F9C | E8 8BB0FEFF       | call acid burn.41AA58              |
0042F9C | 8B45 F0           | mov eax,dword ptr ss:[ebp-10]      | [ebp-10]:"112233"
0042F9D | E8 DB40FDFF       | call acid burn.403AB0              | 判断是否为空
0042F9D | A3 6C174300       | mov dword ptr ds:[43176C],eax      |
0042F9D | 8D55 F0           | lea edx,dword ptr ss:[ebp-10]      | [ebp-10]:"112233"
0042F9D | 8B83 DC010000     | mov eax,dword ptr ds:[ebx+1DC]     | [ebx+1DC]:&"d稝"
0042F9E | E8 70B0FEFF       | call acid burn.41AA58              |

其实就知道。ebp - 10 是我们的字符串, eax指向的地址也是我们的字符串即可,

下面开始第一块算法,

0042F9E | 8B45 F0           | mov eax,dword ptr ss:[ebp-10]      | [ebp-10]:"112233"
byte 是一个字节,所以是把eax的第一个字节给eax高位补0  也就是字符串1   十进制的48
0042F9E | 0FB600            | movzx eax,byte ptr ds:[eax]        |
把eax赋值给esi
0042F9E | 8BF0              | mov esi,eax                        | esi:&"d稝"
esi 左移3位  esi = eax << 3
0042F9F | C1E6 03           | shl esi,3                          | esi:&"d稝"
esi =  eax << 3 - eax 
0042F9F | 2BF0              | sub esi,eax                        | esi:&"d稝"


下面这些似乎并没有什么用处,他调几遍看看
0042F9F | 8D55 EC           | lea edx,dword ptr ss:[ebp-14]      |
0042F9F | 8B83 DC010000     | mov eax,dword ptr ds:[ebx+1DC]     | [ebx+1DC]:&"d稝"
0042F9F | E8 55B0FEFF       | call acid burn.41AA58              |
0042FA0 | 8B45 EC           | mov eax,dword ptr ss:[ebp-14]      |  

第一块算法用C语言代码来编写如下

char* str = "112233"
int nEax = *(str)
int nEsi = nEax << 3 - nEax

开始分析第二块算法

0042FA0 | 0FB640 01         | movzx eax,byte ptr ds:[eax+1]      |
取第二个字节
0042FA0 | C1E0 04           | shl eax,4                          |
右移四位
0042FA0 | 03F0              | add esi,eax                        | esi:&"d稝"
再加上一个esi 也就是第一块算法的结果
0042FA0 | 8935 54174300     | mov dword ptr ds:[431754],esi      | esi:&"d稝"
把结果存入一个变量中

后面就是没啥用的东西了
0042FA1 | 8D55 F0           | lea edx,dword ptr ss:[ebp-10]      | [ebp-10]:"112233"
0042FA1 | 8B83 DC010000     | mov eax,dword ptr ds:[ebx+1DC]     | [ebx+1DC]:&"d稝"
0042FA1 | E8 35B0FEFF       | call acid burn.41AA58              |
0042FA2 | 8B45 F0           | mov eax,dword ptr ss:[ebp-10]      | [ebp-10]:"112233"

还原还原如下:

char* str = "112233"
int nEax = *(str)
int nEsi = nEax << 3 - nEax
int nTmp = *(str+1) << 4 + nEsi

这里其实nTmp才是唯一的一个全局变量,其他的都不是,。只是为了方便看,所以我这样写的。

继续往下写

0042FA2 | 0FB640 03         | movzx eax,byte ptr ds:[eax+3]      |
取出第四个字节
0042FA2 | 6BF0 0B           | imul esi,eax,B                     | esi:&"d稝"
乘以0xB 注意这个B是十六进制的


后面又是无用代码了。
0042FA2 | 8D55 EC           | lea edx,dword ptr ss:[ebp-14]      |
0042FA3 | 8B83 DC010000     | mov eax,dword ptr ds:[ebx+1DC]     | [ebx+1DC]:&"d稝"
0042FA3 | E8 1DB0FEFF       | call acid burn.41AA58              |
0042FA3 | 8B45 EC           | mov eax,dword ptr ss:[ebp-14]      |

这里就先不还原了。,后面一起还原

第三块算法

0042FA3 | 0FB640 02         | movzx eax,byte ptr ds:[eax+2]      |
0042FA4 | 6BC0 0E           | imul eax,eax,E                     |
第三个数据乘以0xE 然后加上esi 这一点要细细斟酌,我等下还原算法。
0042FA4 | 03F0              | add esi,eax                        | esi:&"d稝"
0042FA4 | 8935 58174300     | mov dword ptr ds:[431758],esi      | esi:&"d稝"
0042FA4 | A1 6C174300       | mov eax,dword ptr ds:[43176C]      |
0042FA5 | E8 D96EFDFF       | call acid burn.406930              |
如果小于四个字节就直接爆出两个字符串
0042FA5 | B9 74FB4200       | mov ecx,acid burn.42FB74           | 42FB74:"Try Again!"
0042FA6 | BA 80FB4200       | mov edx,acid burn.42FB80           | edx:&"d稝", 42FB80:"Sorry , The serial is incorect !"


406930   这里是我x32dbg的bug无需理会
0040693 | 89FA              | mov edx,edi                        | edi:&"d稝"
0040693 | 89C7              | mov edi,eax                        | edi:&"d稝"
0040693 | B9 FFFFFFFF       | mov ecx,FFFFFFFF                   |
0040693 | 30C0              | xor al,al                          |
0040693 | F2:AE             | repne scasb                        |
0040693 | B8 FEFFFFFF       | mov eax,FFFFFFFE                   |
0040694 | 29C8              | sub eax,ecx                        |
0040694 | 89D7              | mov edi,edx                        | edi:&"d稝"
0040694 | C3                | ret                                |

这一小段汇编其实主要是repne scasb 指令没有见到过。其实他是计算字符串的长度的。遇到0 就停止,结果在ecx里面

这里有一个小插曲

edi = 02C91100
0040693 | F2:AE             | repne scasb                        |
内存中这一行指令 02C91100 31 31 33 33 14 00 00 00 1B 00 00 00 01 00 00 00     1133............ 
也就是说,后面多出来一个14。所以这里他的代码应该是直接这样写的。
int arr[3] = "123" 或者直接malloc字符串个数,这样来计算的

这里我们不管。只需要知道,如果小于四个字节就直接报错了。

后面继续还原, 无用函数这里就不复制了。后面有人能看到github。看一下原汇编指令就知道了

0042FA8 | 0FB600            | movzx eax,byte ptr ds:[eax]        | eax:"1133"
0042FA8 | F72D 50174300     | imul dword ptr ds:[431750]         |
取出第一个字符,与0x431750的值相乘 往上翻看看这个值哪里出现了 其实就是初始值,。赋值了一个0x29
把结果在存到这个里面,然后再乘以2
0042FA9 | A3 50174300       | mov dword ptr ds:[431750],eax      | eax:"1133"
0042FA9 | A1 50174300       | mov eax,dword ptr ds:[431750]      | eax:"1133"
0042FA9 | 0105 50174300     | add dword ptr ds:[431750],eax      | eax:"1133"

后面就是字符串拼接一下了。

"CW-4018-CRACKED"

下面开始还原算法了。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>

const char* cw = "CW";
const char* crackme = "CRACKED";

int main()
{
	char str[10];
	scanf("%s", str);
	int nTmp = *(str + 1) << 4 + *(str) << 3 - *(str);
	int nTmp2 = *(str + 3) * 0xB + *(str + 2) * 0xE;

	if (strlen(str) <= 4) {
		printf("Try Again!");
		printf("Sorry , The serial is incorect !");
	}
	int nTmp3 = *(str) * 0x29 * 2;
	char key[50];
	sprintf(key, "%s-%d-%s", cw, nTmp3, crackme);
	printf("密钥为:%s\n", key);
	system("pause");
	return 0;
}

测试一下

weiran
密钥为:CW-9758-CRACKED
看看是否可行

image

到这里就结束了。后面还会有,160个刷完为止。

posted @ 2024-12-19 09:17  未然king  阅读(4)  评论(0编辑  收藏  举报