起手
- 查壳 Borland Delphi v3.0
- 直接用idr吧
任务
初期的想法是肯定在文本框中有事件,那么看看吧
跟下文本框文字改变事件
- 先看看在名字文本框的文字变化事件中有如下代码段,可以随便输入点东西,在0x00442E60断下后强制修改EIP看看结果,发现OK可以用了.
00442E37 lea edx,[ebp-4]
00442E3A mov eax,dword ptr [ebx+2E0];TPrincipale.Codice:TEdit
00442E40 call TControl.GetText ;取出注册码
00442E45 mov eax,dword ptr [ebp-4]
00442E48 push eax
00442E49 lea edx,[ebp-8]
00442E4C mov eax,dword ptr [ebx+2DC];TPrincipale.Nome:TEdit
00442E52 call TControl.GetText ; 取出名字
00442E57 mov eax,dword ptr [ebp-8] ;ax name
00442E5A pop edx ;code
00442E5B call 00442A3C ;这里是OK是否可用的关键
00442E60 test al,al ;等于0么
00442E62> je 00442E73 ;
00442E64 mov dl,1 ;不是0可用
00442E66 mov eax,dword ptr [ebx+2CC] ;;TPrincipale.Ok:TButton
00442E6C mov ecx,dword ptr [eax]
00442E6E call dword ptr [ecx+60];TControl.SetEnabled
00442E71> jmp 00442E80 ;是0不可用
00442E73 xor edx,edx
00442E75 mov eax,dword ptr [ebx+2CC];TPrincipale.Ok:TButton
00442E7B mov ecx,dword ptr [eax]
00442E7D call dword ptr [ecx+60];TControl.SetEnabled
00442A3C
00442A68 mov eax,dword ptr [ebp-Name]
00442A6B call @LStrLen
00442A70 cmp eax,5 ;名字不能小于等于5
00442A73> jle 00442AC8
00442A75 mov eax,dword ptr [ebp-Name]
00442A78 call @LStrLen
00442A7D mov ebx,eax
00442A7F mov eax,dword ptr [ebp-Name]
00442A82 call @LStrLen
00442A87 mov edx,eax
00442A89 dec edx
00442A8A test edx,edx ; edx长度
00442A8C> jle 00442AAE ;;多余的代码
00442A8E mov eax,1
00442A93 mov ecx,dword ptr [ebp-Name]
00442A96 movzx ecx,byte ptr [ecx+eax-1]
00442A9B mov esi,dword ptr [ebp-Name]
00442A9E movzx esi,byte ptr [esi+eax]
00442AA2 imul ecx,esi ;字符第n-1个x第n个 * n n从1开始
00442AA5 imul ecx,eax
00442AA8 add ebx,ecx ;长度+ 刚才算出来的
00442AAA inc eax
00442AAB dec edx ;长度-1 循环n字
00442AAC> jne 00442A93
00442AAE mov eax,dword ptr [ebp-Code]
00442AB1 call StrToInt ;注册码
00442AB6 sub ebx,eax
00442AB8 cmp ebx,29A ;相减=0x29
00442ABE> jne 00442AC4
00442AC0 mov bl,1 ;相等就ebx=1
00442AC2> jmp 00442ACA
00442AC4 xor ebx,ebx ;不等就ebx=0
00442AC6> jmp 00442ACA
写下如下代码
重启后输入发现正确.OK有效了.
static string RegCode(string userName)
{
int nLen = userName.Length;
if (nLen<=5)
{
return "";
}
int ebx = nLen;
int eax = 1;
int edx = nLen - 1;
do
{
ebx = userName[eax] * userName[eax - 1] * eax + ebx;
edx--;eax++;
} while (edx > 0);
ebx-=0x29A;
return $"{ebx}";
}
接着看OK按钮的
由代码可知,首先要让Cancella不可见才能继续点OK,所以现在还不能点OK,
00442D7A mov eax,dword ptr [ebx+2D0];TPrincipale.Cancella:TButton
00442D80 cmp byte ptr [eax+47],1; Cancella按钮可见么 TButton.FVisible:Boolean
00442D84> jne 00442D98
00442D86 mov edx,442E00;'0' '可见,那么吧code文本清空
00442D8B mov eax,dword ptr [ebx+2E0];TPrincipale.Codice:TEdit
00442D91 call TControl.SetText
00442D96> jmp 00442DD7
00442D98 lea edx,[ebp-4] ;如果Cancella不可见
00442D9B mov eax,dword ptr [ebx+2E0];TPrincipale.Codice:TEdit
00442DA1 call TControl.GetText
00442DA6 mov eax,dword ptr [ebp-4]
00442DA9 call StrToInt
00442DAE push eax
00442DAF lea edx,[ebp-4]
00442DB2 mov eax,dword ptr [ebx+2DC];TPrincipale.Nome:TEdit
00442DB8 call TControl.GetText
00442DBD mov eax,dword ptr [ebp-4]
00442DC0 pop edx
00442DC1 call 00442BA0
00442DC6 test al,al ;必须返回1
00442DC8> je 00442DD7 ;
00442DCA xor edx,edx ; 使得OK不可见
00442DCC mov eax,dword ptr [ebx+2CC];TPrincipale.Ok:TButton
00442DD2 call TControl.SetVisible
看Cancella的
实在没地方看了,那就看看这个吧,感觉就是cancel.所以开始也就没注意看了.
结果,大跌眼镜,00442AF4会使得Cancella不可见,Ok可以按下,卧槽,感情刚才文本框的就是都是白玩了.作者真是坏透了
00442EBE lea edx,[ebp-4]
00442EC1 mov eax,dword ptr [ebx+2E0];TPrincipale.Codice:TEdit
00442EC7 call TControl.GetText
00442ECC mov eax,dword ptr [ebp-4]
00442ECF call StrToInt
00442ED4 push eax
00442ED5 lea edx,[ebp-4]
00442ED8 mov eax,dword ptr [ebx+2DC];TPrincipale.Nome:TEdit
00442EDE call TControl.GetText
00442EE3 mov eax,dword ptr [ebp-4]
00442EE6 pop edx
00442EE7 call 00442AF4
00442EEC test al,al
00442EEE> je 00442F0C
00442EF0 xor edx,edx ;如果返回0 则设定cancella不可见
00442EF2 mov eax,dword ptr [ebx+2D0];TPrincipale.Cancella:TButton
00442EF8 call TControl.SetVisible
00442EFD mov dl,1 ;Ok有效可以点击
00442EFF mov eax,dword ptr [ebx+2CC];TPrincipale.Ok:TButton
00442F05 mov ecx,dword ptr [eax]
00442F07 call dword ptr [ecx+60];TControl.SetEnabled
00442AF4
00442B25 mov eax,dword ptr [ebp-Name]
00442B28 movzx eax,byte ptr [eax+4] ;第5个字母asc/7
00442B2C mov ecx,7
00442B31 xor edx,edx
00442B33 div eax,ecx ;=eax/ecx,商入eax,余数入edx
00442B35 mov eax,edx
00442B37 add eax,2 ;余数加2
00442B3A call 00442A20 ;阶乘
00442B3F mov esi,eax ;放入esi
00442B41 xor ebx,ebx
00442B43 mov eax,dword ptr [ebp-Name]
00442B46 call @LStrLen
00442B4B test eax,eax
00442B4D> jle 00442B65
00442B4F mov edx,1
00442B54 mov ecx,dword ptr [ebp-Name]
00442B57 movzx ecx,byte ptr [ecx+edx-1]
00442B5C imul ecx,esi ;ebx=n位字符*esi + ebx
00442B5F add ebx,ecx
00442B61 inc edx
00442B62 dec eax
00442B63> jne 00442B54
00442B65 sub ebx,dword ptr [ebp-Code]
00442B68 cmp ebx,7A69
00442B6E> jne 00442B74
00442B70 mov bl,1
00442B72> jmp 00442B7A
如下代码
cancella不可见了
static string RegCode2(string userName)
{
int nLen = userName.Length;
if (nLen <= 5)
{
return "";
}
int esi = (userName[4] % 7) + 2;
esi = Fact(esi);//阶乘
int ebx = 0;
int eax = 1;
int edx = nLen;
do
{
ebx = userName[eax-1] * esi + ebx;
edx--; eax++;
} while (edx > 0);
ebx -= 0x7A69;
return $"{ebx}";
}
好了,按下Ok的条件满足
关键的call 00442BA0
00442BC8 lea edx,[ebp-pCode]
00442BCB mov eax,esi ;code
00442BCD call IntToStr ;code转字串
00442BD2 lea eax,[ebp-0C]
00442BD5 mov edx,dword ptr [ebp-pCode]
00442BD8 call @LStrLAsg ;复制一份Code的字符串
00442BDD mov eax,dword ptr [ebp-pCode]
00442BE0 call @LStrLen
00442BE5 cmp eax,5 ;要求大于等于5长度
00442BE8> jle 00442C4A
00442BEA mov eax,dword ptr [ebp-pCode]
00442BED call @LStrLen
00442BF2 mov esi,eax
00442BF4 cmp esi,1
00442BF7> jl 00442C28
00442BF9 lea eax,[ebp-0C]
00442BFC call UniqueString ;独占使用
00442C01 lea eax,[eax+esi-1] ;指向处理的byte
00442C05 push eax
00442C06 mov eax,dword ptr [ebp-pCode]
00442C09 movzx eax,byte ptr [eax+esi-1] ;倒过来取值
00442C0E imul eax ;eax=eax*eax
00442C10 movsx eax,ax ;取出低16位
00442C13 imul esi ;再乘esi=code字串的长度
00442C15 mov ecx,19
00442C1A cdq
00442C1B idiv eax,ecx ;eax/0x19 商eax 余数edx
00442C1D add edx,41 ;余数+0x41
00442C20 pop eax ;;第n位指针
00442C21 mov byte ptr [eax],dl ;edx低8位赋值
00442C23 dec esi
00442C24 test esi,esi
00442C26> jne 00442BF9
00442C28 mov eax,dword ptr [ebp-0C] ;新的字串和Name比较
00442C2B mov edx,dword ptr [ebp-Name]
00442C2E call @LStrCmp
00442C33> jne 00442C4C
00442C35 mov eax,dword ptr [ebp-Name]
00442C38 mov edx,dword ptr [ebp-0C]
00442C3B call @LStrCmp
00442C40> jne 00442C46
00442C42 mov bl,1 ;相等就返回1
编写代码
运行后,得到一个用户名,输入点OK,任务完成.
static string RegCode3(string code)
{
int nLen = code.Length;
if (nLen <= 5)
{
return "";
}
byte[] bCode = Encoding.Default.GetBytes(code);
int esi = nLen;
do
{
int eax = bCode[esi-1];
eax = ((eax * eax*esi) & 0xffff) % 0x19;
eax += 0x41;
bCode[esi - 1] = (byte)(eax & 0xff);
esi-- ;
} while (esi > 0);
return Encoding.Default.GetString(bCode);
}
总结
- 注册流程
- 先输入一个用户名,运行RegCode2得到注册码,点cancella,cancella消失
- 然后再用这个注册码运行RegCode3得到一个用户名,填入后点OK.OK按钮消失,任务完成
- 人心险恶啊.大家多多保重.