-
-
[原创]解密教学第6章序列号方式之习题九分析
-
发表于: 2008-10-27 21:15 3503
-
学完《加密解密三版》的第5章(常见的演示版保护技术),就把看雪论坛上的解密教学第6章第1小节中的习题做了一遍。发现自己对delphi或MFC的程序运行机制还是不太了解,部分还是借助OD动态分析才能确认,这让我很头疼。今天我把习题九的分析写出来,希望能给一些像我一样的小菜带来些帮助。同时也求助大侠们,帮我解解惑,在此万分感谢。
步骤一、运行程序查看提示信息
运行CRKME4.EXE,输入用户名yzlyzl,序列号123456,点击[check]按钮,跳出对话框提示“Bad Name or Serial Number ”。
步骤二、运行PEiD.exe查看该程序的实现语言
运行PEiD.exe,将CRKME4.EXE拉进来,可以看到提示“Borland Delphi 3.0”
步骤三、查找[check]按钮的点击事件的代码位置
运行资源文件ResHacker.exe,将CRKME4.EXE拉进来,定位[RCData]->[TFORM1]。查找[check]按钮,得到下面数据:
object Button1: TButton
Left = -1
Top = 98
Width = 66
Height = 23
Caption = 'Check'
Font.Charset = DEFAULT_CHARSET
Font.Color = clAqua
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ParentFont = False
TabOrder = 0
OnClick = Button1Click //这里是按钮事件
end
打开二进制文本工具(这里我用的是UltraEdit91),将CRKME4.EXE拉进来,点击[查找]按钮,输入Button1Click,勾上[查找ASCII]。这样我们可以找到如下代码:
0002cc60h:73 65 31 43 6c 69 63 6b 13 00 d4 da 42 00 0c 42;selClick..在B..B
0002cc70h:75 74 74 6F 6e 31 43 6C 69 63 6B ;utton1Click...
红色字体的上一个字节0C代表该字符长度,再上去4个字节代表该按钮事件的地址,即:0042dad4
(PS: 步骤三是看一些大侠的分析学上的,但是我不清楚为什么是这样。)
疑惑1:就是为什么说再上去四个字节就代表按钮事件的地址?如果大家都知道这个地方,那么这个地方不会被修改吗?如果被修改,那又怎么知道他的真实地址在哪里?
步骤四、用IDA加载CRKME4.EXE,定位0042dad4按钮事件
打开IDA,将CRKME4.EXE拖进来。因为这是Delphi3.0的程序,所以设置IDA的FLIRT(File->Load file->FLIRT signature file)为d3vcl。
在IDA上按键盘G,输入0042dad4,定位[Check]按钮事件
步骤五、分析[check]按钮事件
代码如下:
CODE:0042DAD4 CheckClick proc near ; DATA XREF: CODE:0042D86Ao
CODE:0042DAD4
CODE:0042DAD4 var_8 = dword ptr -8
CODE:0042DAD4 var_4 = dword ptr -4
CODE:0042DAD4
CODE:0042DAD4 push ebp
CODE:0042DAD5 mov ebp, esp
CODE:0042DAD7 push 0
CODE:0042DAD9 push 0
CODE:0042DADB push ebx
CODE:0042DADC push esi
CODE:0042DADD push edi
CODE:0042DADE mov ebx, eax
CODE:0042DAE0 mov esi, offset unk_42F75C
CODE:0042DAE5 mov edi, offset unk_42F764
CODE:0042DAEA xor eax, eax
CODE:0042DAEC push ebp
CODE:0042DAED push offset loc_42DD0E
CODE:0042DAF2 push dword ptr fs:[eax]
CODE:0042DAF5 mov fs:[eax], esp
CODE:0042DAF8 mov eax, 4
CODE:0042DAFD call @@GetMem ; __linkproc__ GetMem
CODE:0042DB02 mov ds:lpVolumeSerialNumber, eax
CODE:0042DB07 push 0 ; nFileSystemNameSize
CODE:0042DB09 push 0 ; lpFileSystemNameBuffer
CODE:0042DB0B push offset FileSystemFlags ; lpFileSystemFlags
CODE:0042DB10 push offset MaximumComponentLength ; lpMaximumComponentLength
CODE:0042DB15 mov eax, ds:lpVolumeSerialNumber
CODE:0042DB1A push eax ; lpVolumeSerialNumber
CODE:0042DB1B push 0 ; nVolumeNameSize
CODE:0042DB1D push 0 ; lpVolumeNameBuffer
CODE:0042DB1F push 0 ; lpRootPathName
CODE:0042DB21 call GetVolumeInformationA
CODE:0042DB26 mov eax, ds:lpVolumeSerialNumber
CODE:0042DB2B mov eax, [eax]
CODE:0042DB2D mov ds:dword_42F750, eax
CODE:0042DB32 lea edx, [ebp+var_4]
CODE:0042DB35 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DB3B call @TControl@GetText ; TControl::GetText
CODE:0042DB40 cmp [ebp+var_4], 0 ; [ebp+var_4]=Name的值
CODE:0042DB44 jnz short loc_42DB60 ; 未输入用户名则继续执行并提示出错!
CODE:0042DB46 push 0
CODE:0042DB48 mov cx, word_42DD1C
CODE:0042DB4F mov dl, 2
CODE:0042DB51 mov eax, offset aPleaseTypInYou ; "Please typ in your name !!"
CODE:0042DB56 call @MessageDlg
CODE:0042DB5B jmp loc_42DCF0
CODE:0042DB60 ; ---------------------------------------------------------------------------
CODE:0042DB60
CODE:0042DB60 loc_42DB60: ; CODE XREF: CheckClick+70j
CODE:0042DB60 lea edx, [ebp+var_4]
CODE:0042DB63 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DB69 call @TControl@GetText ; TControl::GetText
CODE:0042DB6E mov eax, [ebp+var_4]
CODE:0042DB71 call @@LStrLen ; __linkproc__ LStrLen
CODE:0042DB76 cmp eax, 6
CODE:0042DB79 jge short loc_42DB95 ; 判断用户名长度是否小于6,小于则出错
CODE:0042DB7B push 0
CODE:0042DB7D mov cx, word_42DD1C
CODE:0042DB84 mov dl, 2
CODE:0042DB86 mov eax, offset aTypeAtLeast6Ch ; "Type at least 6 chars for your name! !"
CODE:0042DB8B call @MessageDlg
CODE:0042DB90 jmp loc_42DCF0
CODE:0042DB95 ; ---------------------------------------------------------------------------
CODE:0042DB95
CODE:0042DB95 loc_42DB95: ; CODE XREF: CheckClick+A5j
CODE:0042DB95 lea edx, [ebp+var_4]
CODE:0042DB98 mov eax, [ebx+1E4h] ; [ebx+1E4h]=Serial控件
CODE:0042DB9E call @TControl@GetText ; TControl::GetText
CODE:0042DBA3 cmp [ebp+var_4], 0
CODE:0042DBA7 jnz short loc_42DBC3 ; 未输入序列号则继续执行并提示出错
CODE:0042DBA9 push 0
CODE:0042DBAB mov cx, word_42DD1C
CODE:0042DBB2 mov dl, 2
CODE:0042DBB4 mov eax, offset aPleaseEnterYou ; "Please enter your serial !"
CODE:0042DBB9 call @MessageDlg
CODE:0042DBBE jmp loc_42DCF0
CODE:0042DBC3 ; ---------------------------------------------------------------------------
CODE:0042DBC3
CODE:0042DBC3 loc_42DBC3: ; CODE XREF: CheckClick+D3j
CODE:0042DBC3 mov eax, edi
CODE:0042DBC5 call @@LStrClr ; __linkproc__ LStrClr
CODE:0042DBCA mov dword ptr [esi], 2
CODE:0042DBD0
CODE:0042DBD0 loc_42DBD0: ; CODE XREF: CheckClick+12Bj
CODE:0042DBD0 lea edx, [ebp+var_4]
CODE:0042DBD3 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DBD9 call @TControl@GetText ; TControl::GetText
CODE:0042DBDE mov eax, [ebp+var_4]
CODE:0042DBE1 mov edx, [esi]
CODE:0042DBE3 movzx eax, byte ptr [eax+edx-1] ; eax = Name[i+1]
CODE:0042DBE8 lea edx, [ebp+var_8]
CODE:0042DBEB call @IntToStr
CODE:0042DBF0 mov edx, [ebp+var_8]
CODE:0042DBF3 mov eax, edi ; 将各个字符转换为数字字符串连接到[edi]
CODE:0042DBF5 call @@LStrCat ; __linkproc__ LStrCat
CODE:0042DBFA inc dword ptr [esi] ; [esi]:2 ~ 6
CODE:0042DBFC cmp dword ptr [esi], 7
CODE:0042DBFF jnz short loc_42DBD0
CODE:0042DC01 lea eax, [ebp+var_8]
CODE:0042DC04 push eax
CODE:0042DC05 mov ecx, 3
CODE:0042DC0A mov edx, 1
CODE:0042DC0F mov eax, [edi]
CODE:0042DC11 call @@LStrCopy ; 获取转换后的前三个字符,保存在[ebp+var_8]
CODE:0042DC16 mov eax, [ebp+var_8]
CODE:0042DC19 call @StrToInt
CODE:0042DC1E mov ds:dword_42F758, eax ; 保存算子
CODE:0042DC23 mov eax, edi
CODE:0042DC25 call @@LStrClr ; 清除字符串
CODE:0042DC2A mov eax, ebx
CODE:0042DC2C call sub_42D8E4 ; *dword_42F758 = (((*dword_42F758 * 6)/3 + 0x10)*2)*9 ^ 5
CODE:0042DC2C ; *dword_42F750 = (((*dword_42F750 << 2)/3)^3) + 0x40
CODE:0042DC31 mov eax, ds:dword_42F750
CODE:0042DC36 mov ds:dword_42F750, eax
CODE:0042DC3B mov eax, ebx
CODE:0042DC3D call sub_42D934 ; *dword_42F758 = ((*dword_42F758 * 6 / 2) + 0x0D)*0x36;
CODE:0042DC3D ; *dword_42F758 = (*dword_42F758 << 5) + *dword_42F758;
CODE:0042DC3D ; *dword_42F758 = *dword_42F758 ^ 0x10;
CODE:0042DC3D ;
CODE:0042DC3D ; *dword_42F750 = (((*dword_42F750 * 6)/5)^0x25) + 0x27;
CODE:0042DC42 mov eax, ds:dword_42F758
CODE:0042DC47 mov ds:dword_42F758, eax
CODE:0042DC4C mov eax, ebx
CODE:0042DC4E call sub_42D988 ; *dword_42F758 = ((*dword_42F758 * 6)/3 + 0x0d)*6;
CODE:0042DC4E ; *dword_42F758 = (*dword_42F758 * 0x59)^0x9;
CODE:0042DC4E ;
CODE:0042DC4E ; *dword_42F750 = ((*dword_42F750 * 5)^0x22)+3;
CODE:0042DC53 mov eax, ebx
CODE:0042DC55 call sub_42D9D8 ; int temp = *dword_42F758 % 2;
CODE:0042DC55 ;
CODE:0042DC55 ; *dword_42F758 = *dword_42F758 / 2;
CODE:0042DC55 ; if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
CODE:0042DC55 ; *dword_42F758 = ((*dword_42F758 + 0x10)*3)^6;
CODE:0042DC55 ;
CODE:0042DC55 ; *dword_42F750 = (((*dword_42F750 * 0x2B)/3)^3) + 0x22;
CODE:0042DC5A mov eax, ds:dword_42F758
CODE:0042DC5F mov ds:dword_42F758, eax
CODE:0042DC64 mov eax, ebx
CODE:0042DC66 call sub_42DA1C
CODE:0042DC6B mov eax, ebx
CODE:0042DC6D call sub_42DA28
CODE:0042DC72 mov eax, ds:dword_42F758
CODE:0042DC77 mov ds:dword_42F758, eax
CODE:0042DC7C mov eax, ebx
CODE:0042DC7E call sub_42DA34 ; int cf = *dword_42F758 & 0x1;
CODE:0042DC7E ;
CODE:0042DC7E ; *dword_42F758 = *dword_42F758 / 2;
CODE:0042DC7E ; if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + cf;
CODE:0042DC7E ; *dword_42F758 = (((*dword_42F758 + 1)*6)<<3)^6;
CODE:0042DC7E ;
CODE:0042DC7E ; *dword_42F750 = *dword_42F750 * 3;
CODE:0042DC7E ; if(*dword_42F750 < 0) *dword_42F750 = *dword_42F750 + 3;
CODE:0042DC7E ; *dword_42F750 = ((*dword_42F750 / 4)^0x22) + 4;
CODE:0042DC83 mov eax, ebx
CODE:0042DC85 call sub_42DA7C ; [dword_42F750] = [dword_42F750] * 3
CODE:0042DC8A mov eax, ebx
CODE:0042DC8C call sub_42DA9C ; *dword_42F758 = (*dword_42F758 ^ 2)*6;
CODE:0042DC8C ; *dword_42F750 = (*dword_42F750 << 2)+4;
CODE:0042DC91 mov eax, ds:dword_42F750
CODE:0042DC96 add ds:dword_42F758, eax ; [dword_42F758] = [dword_42F758] + [dword_42F750]
CODE:0042DC9C lea edx, [ebp+var_4]
CODE:0042DC9F mov eax, [ebx+1E4h] ; 序列号
CODE:0042DCA5 call @TControl@GetText ; TControl::GetText
CODE:0042DCAA mov eax, [ebp+var_4]
CODE:0042DCAD call @StrToInt ; 将输入的序列号转化为对应的数值
CODE:0042DCB2 mov ds:dword_42F760, eax
CODE:0042DCB7 mov eax, ds:dword_42F758
CODE:0042DCBC cmp eax, ds:dword_42F760
CODE:0042DCC2 jnz short loc_42DCDB
CODE:0042DCC4 push 0
CODE:0042DCC6 mov cx, word_42DD1C
CODE:0042DCCD mov dl, 2
CODE:0042DCCF mov eax, offset aGoodSerialThan ; "Good Serial, Thanks For trying this Cra"...
CODE:0042DCD4 call @MessageDlg
CODE:0042DCD9 jmp short loc_42DCF0
CODE:0042DCDB ; ---------------------------------------------------------------------------
CODE:0042DCDB
CODE:0042DCDB loc_42DCDB: ; CODE XREF: CheckClick+1EEj
CODE:0042DCDB push 0
CODE:0042DCDD mov cx, word_42DD1C
CODE:0042DCE4 mov dl, 2
CODE:0042DCE6 mov eax, offset aBadNameOrSeria ; "Bad Name Or Serial Number !!!!!"
CODE:0042DCEB call @MessageDlg
CODE:0042DCF0
CODE:0042DCF0 loc_42DCF0: ; CODE XREF: CheckClick+87j
CODE:0042DCF0 ; CheckClick+BCj ...
CODE:0042DCF0 xor eax, eax
CODE:0042DCF2 pop edx
CODE:0042DCF3 pop ecx
CODE:0042DCF4 pop ecx
CODE:0042DCF5 mov fs:[eax], edx
CODE:0042DCF8 push offset loc_42DD15
CODE:0042DCFD
CODE:0042DCFD loc_42DCFD: ; CODE XREF: CheckClick+23Fj
CODE:0042DCFD lea eax, [ebp+var_8]
CODE:0042DD00 call @@LStrClr ; __linkproc__ LStrClr
CODE:0042DD05 lea eax, [ebp+var_4]
CODE:0042DD08 call @@LStrClr ; __linkproc__ LStrClr
CODE:0042DD0D retn
CODE:0042DD0E ; ---------------------------------------------------------------------------
CODE:0042DD0E
CODE:0042DD0E loc_42DD0E: ; DATA XREF: CheckClick+19o
CODE:0042DD0E jmp @@HandleFinally ; __linkproc__ HandleFinally
CODE:0042DD13 ; ---------------------------------------------------------------------------
CODE:0042DD13 jmp short loc_42DCFD
CODE:0042DD15 ; ---------------------------------------------------------------------------
CODE:0042DD15
CODE:0042DD15 loc_42DD15: ; CODE XREF: CheckClick+239j
CODE:0042DD15 ; DATA XREF: CheckClick+224o
CODE:0042DD15 pop edi
CODE:0042DD16 pop esi
CODE:0042DD17 pop ebx
CODE:0042DD18 pop ecx
CODE:0042DD19 pop ecx
CODE:0042DD1A pop ebp
CODE:0042DD1B retn
CODE:0042DD1B CheckClick endp
疑惑2、
CODE:0042DB35 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name的文本控件
对于这段代码,我怎么知道它是代表哪个控件的呢?(这个我是用OD动态分析才知道的)
步骤六、编写注册机
代码如下:
#include <stdio.h>
#include <windows.h>
// by Yzl 2008-10-27
void sub_42D8E4(int *dword_42F758,int *dword_42F750)
{
*dword_42F758 = (((*dword_42F758 * 6)/3 + 0x10)*2)*9;
*dword_42F758 = *dword_42F758 ^ 5;
*dword_42F750 = (((*dword_42F750 << 2)/3)^3) + 0x40;
}
void sub_42D934(int *dword_42F758,int *dword_42F750)
{
int temp = (*dword_42F758 * 6) & 0x1;
*dword_42F758 = (*dword_42F758 * 6) / 2;
if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
*dword_42F758 = (*dword_42F758 + 0x0D)*0x36;
*dword_42F758 = (*dword_42F758 << 5) + *dword_42F758;
*dword_42F758 = *dword_42F758 ^ 0x10;
*dword_42F750 = (((*dword_42F750 * 6)/5)^0x25) + 0x27;
}
void sub_42D988(int *dword_42F758,int *dword_42F750)
{
*dword_42F758 = ((*dword_42F758 * 6)/3 + 0x0d)*6;
*dword_42F758 = (*dword_42F758 * 0x59)^0x9;
*dword_42F750 = ((*dword_42F750 * 5)^0x22)+3;
}
void sub_42D9D8(int *dword_42F758,int *dword_42F750)
{
int temp = *dword_42F758 & 0x1;
*dword_42F758 = *dword_42F758 / 2;
if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
*dword_42F758 = ((*dword_42F758 + 0x10)*3)^6;
*dword_42F750 = (((*dword_42F750 * 0x2B)/3)^3) + 0x22;
}
void sub_42DA34(int *dword_42F758,int *dword_42F750)
{
int cf = *dword_42F758 & 0x1;
*dword_42F758 = *dword_42F758 / 2;
if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + cf;
*dword_42F758 = (((*dword_42F758 + 1)*6)<<3)^6;
*dword_42F750 = *dword_42F750 * 3;
if(*dword_42F750 < 0) *dword_42F750 = *dword_42F750 + 3;
*dword_42F750 = ((*dword_42F750 / 4)^0x22) + 4;
}
void sub_42DA7C(int *dword_42F758,int *dword_42F750)
{
*dword_42F750 = *dword_42F750 * 3;
printf("dword_42F758=0x%X\n",*dword_42F758);
printf("dword_42F750=0x%X\n",*dword_42F750);
}
void sub_42DA9C(int *dword_42F758,int *dword_42F750)
{
*dword_42F758 = (*dword_42F758 ^ 2)*6;
*dword_42F750 = (*dword_42F750 << 2)+4;
printf("dword_42F758=0x%X\n",*dword_42F758);
printf("dword_42F750=0x%X\n",*dword_42F750);
}
void KeyGen(char *name, int len /*= 7*/)
{
DWORD fileSystemFlags,maximumComponentLength,volumeSerialNumber;
int i = 2,dword_42F758,dword_42F750;
char buf1[128] = {0};
char buf2[128] = {0};
GetVolumeInformation(0,0,0,&volumeSerialNumber,
&maximumComponentLength,&fileSystemFlags,0,0);
dword_42F750 = volumeSerialNumber;
for(; i < 7; i ++)
{
sprintf(buf1,"%d",name[i - 1]);
strcat(buf2,buf1);
}
sscanf(buf2,"%3d",&dword_42F758);
sub_42D8E4(&dword_42F758,&dword_42F750);
sub_42D934(&dword_42F758,&dword_42F750);
sub_42D988(&dword_42F758,&dword_42F750);
sub_42D9D8(&dword_42F758,&dword_42F750);
sub_42DA34(&dword_42F758,&dword_42F750);
sub_42DA7C(&dword_42F758,&dword_42F750);
sub_42DA9C(&dword_42F758,&dword_42F750);
printf("name=%s,serial=%d",name,dword_42F758 + dword_42F750);
}
int main(int argc,char **argv)
{
if(argc != 2)
{
printf("Usage: KeyGen [username]");
return 1;
}
if(strlen(argv[1]) <= 5)
{
printf("Username'Length must be greater than 5");
return 1;
}
KeyGen(argv[1],strlen(argv[1]));
return 0;
}
编译:
cl KeyGen.c
运行
KeyGen yzlyzl
得到
name=yzlyzl,serial=-850023320
疑惑3、其中一段Delphi程序的实现不是特别理解,求助一下大家:
CODE:00403544 @@LStrClr proc near ; CODE XREF: __linkproc__ LStrFromPCharLen+23p
CODE:00403544 ; __linkproc__ LStrFromPWCharLen+16p ...
CODE:00403544 mov edx, [eax]
CODE:00403546 test edx, edx
CODE:00403548 jz short locret_403565
CODE:0040354A mov dword ptr [eax], 0
CODE:00403550 mov ecx, [edx-8] //为什么这么做,什么意思?
CODE:00403553 dec ecx
CODE:00403554 jl short locret_403565
CODE:00403556 mov [edx-8], ecx
CODE:00403559 jnz short locret_403565
CODE:0040355B push eax
CODE:0040355C lea eax, [edx-8]
CODE:0040355F call @@FreeMem ; __linkproc__ FreeMem
CODE:00403564 pop eax
CODE:00403565
CODE:00403565 locret_403565: ; CODE XREF: __linkproc__ LStrClr+4j
CODE:00403565 ; __linkproc__ LStrClr+10j ...
CODE:00403565 retn
CODE:00403565 @@LStrClr endp
最后:感觉自己对Delphi程序的分析过于依赖IDA的FLIRT来理解它内置的函数,即便如此,有时看到一些内置函数还是感觉云里雾里,不知道有没有好的资料可以针对Delphi进行更系统的研究?谢谢大家。
步骤一、运行程序查看提示信息
运行CRKME4.EXE,输入用户名yzlyzl,序列号123456,点击[check]按钮,跳出对话框提示“Bad Name or Serial Number ”。
步骤二、运行PEiD.exe查看该程序的实现语言
运行PEiD.exe,将CRKME4.EXE拉进来,可以看到提示“Borland Delphi 3.0”
步骤三、查找[check]按钮的点击事件的代码位置
运行资源文件ResHacker.exe,将CRKME4.EXE拉进来,定位[RCData]->[TFORM1]。查找[check]按钮,得到下面数据:
object Button1: TButton
Left = -1
Top = 98
Width = 66
Height = 23
Caption = 'Check'
Font.Charset = DEFAULT_CHARSET
Font.Color = clAqua
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ParentFont = False
TabOrder = 0
OnClick = Button1Click //这里是按钮事件
end
打开二进制文本工具(这里我用的是UltraEdit91),将CRKME4.EXE拉进来,点击[查找]按钮,输入Button1Click,勾上[查找ASCII]。这样我们可以找到如下代码:
0002cc60h:73 65 31 43 6c 69 63 6b 13 00 d4 da 42 00 0c 42;selClick..在B..B
0002cc70h:75 74 74 6F 6e 31 43 6C 69 63 6B ;utton1Click...
红色字体的上一个字节0C代表该字符长度,再上去4个字节代表该按钮事件的地址,即:0042dad4
(PS: 步骤三是看一些大侠的分析学上的,但是我不清楚为什么是这样。)
疑惑1:就是为什么说再上去四个字节就代表按钮事件的地址?如果大家都知道这个地方,那么这个地方不会被修改吗?如果被修改,那又怎么知道他的真实地址在哪里?
步骤四、用IDA加载CRKME4.EXE,定位0042dad4按钮事件
打开IDA,将CRKME4.EXE拖进来。因为这是Delphi3.0的程序,所以设置IDA的FLIRT(File->Load file->FLIRT signature file)为d3vcl。
在IDA上按键盘G,输入0042dad4,定位[Check]按钮事件
步骤五、分析[check]按钮事件
代码如下:
CODE:0042DAD4 CheckClick proc near ; DATA XREF: CODE:0042D86Ao
CODE:0042DAD4
CODE:0042DAD4 var_8 = dword ptr -8
CODE:0042DAD4 var_4 = dword ptr -4
CODE:0042DAD4
CODE:0042DAD4 push ebp
CODE:0042DAD5 mov ebp, esp
CODE:0042DAD7 push 0
CODE:0042DAD9 push 0
CODE:0042DADB push ebx
CODE:0042DADC push esi
CODE:0042DADD push edi
CODE:0042DADE mov ebx, eax
CODE:0042DAE0 mov esi, offset unk_42F75C
CODE:0042DAE5 mov edi, offset unk_42F764
CODE:0042DAEA xor eax, eax
CODE:0042DAEC push ebp
CODE:0042DAED push offset loc_42DD0E
CODE:0042DAF2 push dword ptr fs:[eax]
CODE:0042DAF5 mov fs:[eax], esp
CODE:0042DAF8 mov eax, 4
CODE:0042DAFD call @@GetMem ; __linkproc__ GetMem
CODE:0042DB02 mov ds:lpVolumeSerialNumber, eax
CODE:0042DB07 push 0 ; nFileSystemNameSize
CODE:0042DB09 push 0 ; lpFileSystemNameBuffer
CODE:0042DB0B push offset FileSystemFlags ; lpFileSystemFlags
CODE:0042DB10 push offset MaximumComponentLength ; lpMaximumComponentLength
CODE:0042DB15 mov eax, ds:lpVolumeSerialNumber
CODE:0042DB1A push eax ; lpVolumeSerialNumber
CODE:0042DB1B push 0 ; nVolumeNameSize
CODE:0042DB1D push 0 ; lpVolumeNameBuffer
CODE:0042DB1F push 0 ; lpRootPathName
CODE:0042DB21 call GetVolumeInformationA
CODE:0042DB26 mov eax, ds:lpVolumeSerialNumber
CODE:0042DB2B mov eax, [eax]
CODE:0042DB2D mov ds:dword_42F750, eax
CODE:0042DB32 lea edx, [ebp+var_4]
CODE:0042DB35 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DB3B call @TControl@GetText ; TControl::GetText
CODE:0042DB40 cmp [ebp+var_4], 0 ; [ebp+var_4]=Name的值
CODE:0042DB44 jnz short loc_42DB60 ; 未输入用户名则继续执行并提示出错!
CODE:0042DB46 push 0
CODE:0042DB48 mov cx, word_42DD1C
CODE:0042DB4F mov dl, 2
CODE:0042DB51 mov eax, offset aPleaseTypInYou ; "Please typ in your name !!"
CODE:0042DB56 call @MessageDlg
CODE:0042DB5B jmp loc_42DCF0
CODE:0042DB60 ; ---------------------------------------------------------------------------
CODE:0042DB60
CODE:0042DB60 loc_42DB60: ; CODE XREF: CheckClick+70j
CODE:0042DB60 lea edx, [ebp+var_4]
CODE:0042DB63 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DB69 call @TControl@GetText ; TControl::GetText
CODE:0042DB6E mov eax, [ebp+var_4]
CODE:0042DB71 call @@LStrLen ; __linkproc__ LStrLen
CODE:0042DB76 cmp eax, 6
CODE:0042DB79 jge short loc_42DB95 ; 判断用户名长度是否小于6,小于则出错
CODE:0042DB7B push 0
CODE:0042DB7D mov cx, word_42DD1C
CODE:0042DB84 mov dl, 2
CODE:0042DB86 mov eax, offset aTypeAtLeast6Ch ; "Type at least 6 chars for your name! !"
CODE:0042DB8B call @MessageDlg
CODE:0042DB90 jmp loc_42DCF0
CODE:0042DB95 ; ---------------------------------------------------------------------------
CODE:0042DB95
CODE:0042DB95 loc_42DB95: ; CODE XREF: CheckClick+A5j
CODE:0042DB95 lea edx, [ebp+var_4]
CODE:0042DB98 mov eax, [ebx+1E4h] ; [ebx+1E4h]=Serial控件
CODE:0042DB9E call @TControl@GetText ; TControl::GetText
CODE:0042DBA3 cmp [ebp+var_4], 0
CODE:0042DBA7 jnz short loc_42DBC3 ; 未输入序列号则继续执行并提示出错
CODE:0042DBA9 push 0
CODE:0042DBAB mov cx, word_42DD1C
CODE:0042DBB2 mov dl, 2
CODE:0042DBB4 mov eax, offset aPleaseEnterYou ; "Please enter your serial !"
CODE:0042DBB9 call @MessageDlg
CODE:0042DBBE jmp loc_42DCF0
CODE:0042DBC3 ; ---------------------------------------------------------------------------
CODE:0042DBC3
CODE:0042DBC3 loc_42DBC3: ; CODE XREF: CheckClick+D3j
CODE:0042DBC3 mov eax, edi
CODE:0042DBC5 call @@LStrClr ; __linkproc__ LStrClr
CODE:0042DBCA mov dword ptr [esi], 2
CODE:0042DBD0
CODE:0042DBD0 loc_42DBD0: ; CODE XREF: CheckClick+12Bj
CODE:0042DBD0 lea edx, [ebp+var_4]
CODE:0042DBD3 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name控件
CODE:0042DBD9 call @TControl@GetText ; TControl::GetText
CODE:0042DBDE mov eax, [ebp+var_4]
CODE:0042DBE1 mov edx, [esi]
CODE:0042DBE3 movzx eax, byte ptr [eax+edx-1] ; eax = Name[i+1]
CODE:0042DBE8 lea edx, [ebp+var_8]
CODE:0042DBEB call @IntToStr
CODE:0042DBF0 mov edx, [ebp+var_8]
CODE:0042DBF3 mov eax, edi ; 将各个字符转换为数字字符串连接到[edi]
CODE:0042DBF5 call @@LStrCat ; __linkproc__ LStrCat
CODE:0042DBFA inc dword ptr [esi] ; [esi]:2 ~ 6
CODE:0042DBFC cmp dword ptr [esi], 7
CODE:0042DBFF jnz short loc_42DBD0
CODE:0042DC01 lea eax, [ebp+var_8]
CODE:0042DC04 push eax
CODE:0042DC05 mov ecx, 3
CODE:0042DC0A mov edx, 1
CODE:0042DC0F mov eax, [edi]
CODE:0042DC11 call @@LStrCopy ; 获取转换后的前三个字符,保存在[ebp+var_8]
CODE:0042DC16 mov eax, [ebp+var_8]
CODE:0042DC19 call @StrToInt
CODE:0042DC1E mov ds:dword_42F758, eax ; 保存算子
CODE:0042DC23 mov eax, edi
CODE:0042DC25 call @@LStrClr ; 清除字符串
CODE:0042DC2A mov eax, ebx
CODE:0042DC2C call sub_42D8E4 ; *dword_42F758 = (((*dword_42F758 * 6)/3 + 0x10)*2)*9 ^ 5
CODE:0042DC2C ; *dword_42F750 = (((*dword_42F750 << 2)/3)^3) + 0x40
CODE:0042DC31 mov eax, ds:dword_42F750
CODE:0042DC36 mov ds:dword_42F750, eax
CODE:0042DC3B mov eax, ebx
CODE:0042DC3D call sub_42D934 ; *dword_42F758 = ((*dword_42F758 * 6 / 2) + 0x0D)*0x36;
CODE:0042DC3D ; *dword_42F758 = (*dword_42F758 << 5) + *dword_42F758;
CODE:0042DC3D ; *dword_42F758 = *dword_42F758 ^ 0x10;
CODE:0042DC3D ;
CODE:0042DC3D ; *dword_42F750 = (((*dword_42F750 * 6)/5)^0x25) + 0x27;
CODE:0042DC42 mov eax, ds:dword_42F758
CODE:0042DC47 mov ds:dword_42F758, eax
CODE:0042DC4C mov eax, ebx
CODE:0042DC4E call sub_42D988 ; *dword_42F758 = ((*dword_42F758 * 6)/3 + 0x0d)*6;
CODE:0042DC4E ; *dword_42F758 = (*dword_42F758 * 0x59)^0x9;
CODE:0042DC4E ;
CODE:0042DC4E ; *dword_42F750 = ((*dword_42F750 * 5)^0x22)+3;
CODE:0042DC53 mov eax, ebx
CODE:0042DC55 call sub_42D9D8 ; int temp = *dword_42F758 % 2;
CODE:0042DC55 ;
CODE:0042DC55 ; *dword_42F758 = *dword_42F758 / 2;
CODE:0042DC55 ; if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
CODE:0042DC55 ; *dword_42F758 = ((*dword_42F758 + 0x10)*3)^6;
CODE:0042DC55 ;
CODE:0042DC55 ; *dword_42F750 = (((*dword_42F750 * 0x2B)/3)^3) + 0x22;
CODE:0042DC5A mov eax, ds:dword_42F758
CODE:0042DC5F mov ds:dword_42F758, eax
CODE:0042DC64 mov eax, ebx
CODE:0042DC66 call sub_42DA1C
CODE:0042DC6B mov eax, ebx
CODE:0042DC6D call sub_42DA28
CODE:0042DC72 mov eax, ds:dword_42F758
CODE:0042DC77 mov ds:dword_42F758, eax
CODE:0042DC7C mov eax, ebx
CODE:0042DC7E call sub_42DA34 ; int cf = *dword_42F758 & 0x1;
CODE:0042DC7E ;
CODE:0042DC7E ; *dword_42F758 = *dword_42F758 / 2;
CODE:0042DC7E ; if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + cf;
CODE:0042DC7E ; *dword_42F758 = (((*dword_42F758 + 1)*6)<<3)^6;
CODE:0042DC7E ;
CODE:0042DC7E ; *dword_42F750 = *dword_42F750 * 3;
CODE:0042DC7E ; if(*dword_42F750 < 0) *dword_42F750 = *dword_42F750 + 3;
CODE:0042DC7E ; *dword_42F750 = ((*dword_42F750 / 4)^0x22) + 4;
CODE:0042DC83 mov eax, ebx
CODE:0042DC85 call sub_42DA7C ; [dword_42F750] = [dword_42F750] * 3
CODE:0042DC8A mov eax, ebx
CODE:0042DC8C call sub_42DA9C ; *dword_42F758 = (*dword_42F758 ^ 2)*6;
CODE:0042DC8C ; *dword_42F750 = (*dword_42F750 << 2)+4;
CODE:0042DC91 mov eax, ds:dword_42F750
CODE:0042DC96 add ds:dword_42F758, eax ; [dword_42F758] = [dword_42F758] + [dword_42F750]
CODE:0042DC9C lea edx, [ebp+var_4]
CODE:0042DC9F mov eax, [ebx+1E4h] ; 序列号
CODE:0042DCA5 call @TControl@GetText ; TControl::GetText
CODE:0042DCAA mov eax, [ebp+var_4]
CODE:0042DCAD call @StrToInt ; 将输入的序列号转化为对应的数值
CODE:0042DCB2 mov ds:dword_42F760, eax
CODE:0042DCB7 mov eax, ds:dword_42F758
CODE:0042DCBC cmp eax, ds:dword_42F760
CODE:0042DCC2 jnz short loc_42DCDB
CODE:0042DCC4 push 0
CODE:0042DCC6 mov cx, word_42DD1C
CODE:0042DCCD mov dl, 2
CODE:0042DCCF mov eax, offset aGoodSerialThan ; "Good Serial, Thanks For trying this Cra"...
CODE:0042DCD4 call @MessageDlg
CODE:0042DCD9 jmp short loc_42DCF0
CODE:0042DCDB ; ---------------------------------------------------------------------------
CODE:0042DCDB
CODE:0042DCDB loc_42DCDB: ; CODE XREF: CheckClick+1EEj
CODE:0042DCDB push 0
CODE:0042DCDD mov cx, word_42DD1C
CODE:0042DCE4 mov dl, 2
CODE:0042DCE6 mov eax, offset aBadNameOrSeria ; "Bad Name Or Serial Number !!!!!"
CODE:0042DCEB call @MessageDlg
CODE:0042DCF0
CODE:0042DCF0 loc_42DCF0: ; CODE XREF: CheckClick+87j
CODE:0042DCF0 ; CheckClick+BCj ...
CODE:0042DCF0 xor eax, eax
CODE:0042DCF2 pop edx
CODE:0042DCF3 pop ecx
CODE:0042DCF4 pop ecx
CODE:0042DCF5 mov fs:[eax], edx
CODE:0042DCF8 push offset loc_42DD15
CODE:0042DCFD
CODE:0042DCFD loc_42DCFD: ; CODE XREF: CheckClick+23Fj
CODE:0042DCFD lea eax, [ebp+var_8]
CODE:0042DD00 call @@LStrClr ; __linkproc__ LStrClr
CODE:0042DD05 lea eax, [ebp+var_4]
CODE:0042DD08 call @@LStrClr ; __linkproc__ LStrClr
CODE:0042DD0D retn
CODE:0042DD0E ; ---------------------------------------------------------------------------
CODE:0042DD0E
CODE:0042DD0E loc_42DD0E: ; DATA XREF: CheckClick+19o
CODE:0042DD0E jmp @@HandleFinally ; __linkproc__ HandleFinally
CODE:0042DD13 ; ---------------------------------------------------------------------------
CODE:0042DD13 jmp short loc_42DCFD
CODE:0042DD15 ; ---------------------------------------------------------------------------
CODE:0042DD15
CODE:0042DD15 loc_42DD15: ; CODE XREF: CheckClick+239j
CODE:0042DD15 ; DATA XREF: CheckClick+224o
CODE:0042DD15 pop edi
CODE:0042DD16 pop esi
CODE:0042DD17 pop ebx
CODE:0042DD18 pop ecx
CODE:0042DD19 pop ecx
CODE:0042DD1A pop ebp
CODE:0042DD1B retn
CODE:0042DD1B CheckClick endp
疑惑2、
CODE:0042DB35 mov eax, [ebx+1E0h] ; [ebx+1E0h]=Name的文本控件
对于这段代码,我怎么知道它是代表哪个控件的呢?(这个我是用OD动态分析才知道的)
步骤六、编写注册机
代码如下:
#include <stdio.h>
#include <windows.h>
// by Yzl 2008-10-27
void sub_42D8E4(int *dword_42F758,int *dword_42F750)
{
*dword_42F758 = (((*dword_42F758 * 6)/3 + 0x10)*2)*9;
*dword_42F758 = *dword_42F758 ^ 5;
*dword_42F750 = (((*dword_42F750 << 2)/3)^3) + 0x40;
}
void sub_42D934(int *dword_42F758,int *dword_42F750)
{
int temp = (*dword_42F758 * 6) & 0x1;
*dword_42F758 = (*dword_42F758 * 6) / 2;
if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
*dword_42F758 = (*dword_42F758 + 0x0D)*0x36;
*dword_42F758 = (*dword_42F758 << 5) + *dword_42F758;
*dword_42F758 = *dword_42F758 ^ 0x10;
*dword_42F750 = (((*dword_42F750 * 6)/5)^0x25) + 0x27;
}
void sub_42D988(int *dword_42F758,int *dword_42F750)
{
*dword_42F758 = ((*dword_42F758 * 6)/3 + 0x0d)*6;
*dword_42F758 = (*dword_42F758 * 0x59)^0x9;
*dword_42F750 = ((*dword_42F750 * 5)^0x22)+3;
}
void sub_42D9D8(int *dword_42F758,int *dword_42F750)
{
int temp = *dword_42F758 & 0x1;
*dword_42F758 = *dword_42F758 / 2;
if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + temp;
*dword_42F758 = ((*dword_42F758 + 0x10)*3)^6;
*dword_42F750 = (((*dword_42F750 * 0x2B)/3)^3) + 0x22;
}
void sub_42DA34(int *dword_42F758,int *dword_42F750)
{
int cf = *dword_42F758 & 0x1;
*dword_42F758 = *dword_42F758 / 2;
if(*dword_42F758 < 0) *dword_42F758 = *dword_42F758 + cf;
*dword_42F758 = (((*dword_42F758 + 1)*6)<<3)^6;
*dword_42F750 = *dword_42F750 * 3;
if(*dword_42F750 < 0) *dword_42F750 = *dword_42F750 + 3;
*dword_42F750 = ((*dword_42F750 / 4)^0x22) + 4;
}
void sub_42DA7C(int *dword_42F758,int *dword_42F750)
{
*dword_42F750 = *dword_42F750 * 3;
printf("dword_42F758=0x%X\n",*dword_42F758);
printf("dword_42F750=0x%X\n",*dword_42F750);
}
void sub_42DA9C(int *dword_42F758,int *dword_42F750)
{
*dword_42F758 = (*dword_42F758 ^ 2)*6;
*dword_42F750 = (*dword_42F750 << 2)+4;
printf("dword_42F758=0x%X\n",*dword_42F758);
printf("dword_42F750=0x%X\n",*dword_42F750);
}
void KeyGen(char *name, int len /*= 7*/)
{
DWORD fileSystemFlags,maximumComponentLength,volumeSerialNumber;
int i = 2,dword_42F758,dword_42F750;
char buf1[128] = {0};
char buf2[128] = {0};
GetVolumeInformation(0,0,0,&volumeSerialNumber,
&maximumComponentLength,&fileSystemFlags,0,0);
dword_42F750 = volumeSerialNumber;
for(; i < 7; i ++)
{
sprintf(buf1,"%d",name[i - 1]);
strcat(buf2,buf1);
}
sscanf(buf2,"%3d",&dword_42F758);
sub_42D8E4(&dword_42F758,&dword_42F750);
sub_42D934(&dword_42F758,&dword_42F750);
sub_42D988(&dword_42F758,&dword_42F750);
sub_42D9D8(&dword_42F758,&dword_42F750);
sub_42DA34(&dword_42F758,&dword_42F750);
sub_42DA7C(&dword_42F758,&dword_42F750);
sub_42DA9C(&dword_42F758,&dword_42F750);
printf("name=%s,serial=%d",name,dword_42F758 + dword_42F750);
}
int main(int argc,char **argv)
{
if(argc != 2)
{
printf("Usage: KeyGen [username]");
return 1;
}
if(strlen(argv[1]) <= 5)
{
printf("Username'Length must be greater than 5");
return 1;
}
KeyGen(argv[1],strlen(argv[1]));
return 0;
}
编译:
cl KeyGen.c
运行
KeyGen yzlyzl
得到
name=yzlyzl,serial=-850023320
疑惑3、其中一段Delphi程序的实现不是特别理解,求助一下大家:
CODE:00403544 @@LStrClr proc near ; CODE XREF: __linkproc__ LStrFromPCharLen+23p
CODE:00403544 ; __linkproc__ LStrFromPWCharLen+16p ...
CODE:00403544 mov edx, [eax]
CODE:00403546 test edx, edx
CODE:00403548 jz short locret_403565
CODE:0040354A mov dword ptr [eax], 0
CODE:00403550 mov ecx, [edx-8] //为什么这么做,什么意思?
CODE:00403553 dec ecx
CODE:00403554 jl short locret_403565
CODE:00403556 mov [edx-8], ecx
CODE:00403559 jnz short locret_403565
CODE:0040355B push eax
CODE:0040355C lea eax, [edx-8]
CODE:0040355F call @@FreeMem ; __linkproc__ FreeMem
CODE:00403564 pop eax
CODE:00403565
CODE:00403565 locret_403565: ; CODE XREF: __linkproc__ LStrClr+4j
CODE:00403565 ; __linkproc__ LStrClr+10j ...
CODE:00403565 retn
CODE:00403565 @@LStrClr endp
最后:感觉自己对Delphi程序的分析过于依赖IDA的FLIRT来理解它内置的函数,即便如此,有时看到一些内置函数还是感觉云里雾里,不知道有没有好的资料可以针对Delphi进行更系统的研究?谢谢大家。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
他的文章
看原图
赞赏
雪币:
留言: