【文章标题】: [原创]CrackMe2.0分析及注册机算法(含VC写的注册机)
【文章作者】: wuwenyao
【作者邮箱】: [email]wuwenyao.gm@gmail.com[/email]
【软件名称】: CrackMe 2.0
【下载地址】: http://www.unpack.cn/viewthread.php?tid=35910&extra=page%3D1&page=1
【使用工具】: ollydbg,IDA,dede
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
第一次写破文,第一次用IDA……,呵呵,太多第一次,发贴留念
有的朋友没有unpack的帐号,搜索了一下,这个crackme在看雪也有:
【原创】今年最后一个CrackMe 2.0
今天发现,作者把源码也发了:
【原创】今年最后一个CrackMe 2.0 源码
--------------------------------------------------------------------------------
【详细过程】
这是UNPACK论坛出的unpackme_007,脱壳相对简单,在此略过。
以下是算法分析:
peid载入脱壳程序,显示Borland Delphi 6.0-7.0
CM是delphi写的
运行脱壳程序,随便填用户名和注册码,跳出对话框“注册码错误,请与软件开发商联系!”
OD载入脱壳程序,随便填用户名和注册码,下断 bp MessageBoxA,点确定,没断下来,程序中止了:(,看来有anti-debug
打开插件选项phant0m,选hide from PEB,点save,ctrl+F2重新载入,点Alt+b,禁用断点,F9运行,随便填用户名和注册码,Alt+b开启断点,F9,断在
77D507EA > 8BFF mov edi, edi
77D507EC 55 push ebp
77D507ED 8BEC mov ebp, esp
77D507EF 833D BC14D777 0>cmp dword ptr [77D714BC], 0
Alt+b,禁用断点,Alt+C,ctrl+F9,切换回程序看到跳框了,点确定,断在
00458FD3 8945 F8 mov dword ptr [ebp-8], eax
00458FD6 33C0 xor eax, eax
00458FD8 5A pop edx
00458FD9 59 pop ecx
再按ctrl+F9 2次来到
004857F4 33C0 xor eax, eax
004857F6 5A pop edx
004857F7 59 pop ecx
004857F8 59 pop ecx
往上一行看到
004857EF E8 F436FDFF call 00458EE8 ; 跳框
跳框是在这里调用的了:)再往上看
004857B8 6A 10 push 10
004857BA 8D55 D0 lea edx, dword ptr [ebp-30]
004857BD B8 6C584800 mov eax, 0048586C ; ASCII "CCE1CABE"
004857C2 E8 85F8FFFF call 0048504C
004857C7 8B45 D0 mov eax, dword ptr [ebp-30]
004857CA E8 E9EBF7FF call 004043B8
004857CF 50 push eax
004857D0 8D55 CC lea edx, dword ptr [ebp-34]
004857D3 B8 B8584800 mov eax, 004858B8 ; ASCII "D7A2B2E1C2EBB4EDCEF3A3ACC7EBD3EBC8EDBCFEBFAAB7A2C9CCC1AACFB5A3A1"
004857D8 E8 6FF8FFFF call 0048504C
004857DD 8B45 CC mov eax, dword ptr [ebp-34]
004857E0 E8 D3EBF7FF call 004043B8
004857E5 8BD0 mov edx, eax
004857E7 A1 0C744800 mov eax, dword ptr [48740C]
004857EC 8B00 mov eax, dword ptr [eax]
004857EE 59 pop ecx
004857EF E8 F436FDFF call 00458EE8 ; 跳框
几个call是在准备跳框用到的数据,再往上看
004856B9 E8 4E3DFBFF call 0043940C
004856BE 8B45 FC mov eax, dword ptr [ebp-4] ; 用户名处理
004856C1 E8 02F9FFFF call 00484FC8 ; 检查用户名
004856C6 84C0 test al, al
004856C8 0F84 EA000000 je 004857B8 ; 跳框
004856CE 8D4D F4 lea ecx, dword ptr [ebp-C]
004856D1 8B15 088D4800 mov edx, dword ptr [488D08]
004856D7 8B83 18030000 mov eax, dword ptr [ebx+318]
004856DD E8 D2FCFFFF call 004853B4
004856E2 8B45 F4 mov eax, dword ptr [ebp-C]
004856E5 8D55 F8 lea edx, dword ptr [ebp-8]
004856E8 E8 132CF8FF call 00408300
004856ED 8B45 F8 mov eax, dword ptr [ebp-8]
004856F0 50 push eax
004856F1 8D55 F0 lea edx, dword ptr [ebp-10]
004856F4 8B83 04030000 mov eax, dword ptr [ebx+304]
004856FA E8 0D3DFBFF call 0043940C
004856FF 8B55 F0 mov edx, dword ptr [ebp-10]
00485702 58 pop eax
00485703 E8 FCEBF7FF call 00404304 ; 关键call
00485708 0F85 AA000000 jnz 004857B8 ; 跳框
0048570E 8D55 E8 lea edx, dword ptr [ebp-18]
00485711 8B83 04030000 mov eax, dword ptr [ebx+304]
00485717 E8 F03CFBFF call 0043940C
0048571C 8B45 E8 mov eax, dword ptr [ebp-18]
0048571F 8D55 EC lea edx, dword ptr [ebp-14]
00485722 E8 E9EFFFFF call 00484710
00485727 8B45 EC mov eax, dword ptr [ebp-14]
0048572A 50 push eax
0048572B 8D55 E4 lea edx, dword ptr [ebp-1C]
0048572E 8B83 FC020000 mov eax, dword ptr [ebx+2FC]
00485734 E8 D33CFBFF call 0043940C
00485739 8D45 E4 lea eax, dword ptr [ebp-1C]
0048573C 50 push eax
0048573D 8D55 E0 lea edx, dword ptr [ebp-20]
00485740 8B83 F8020000 mov eax, dword ptr [ebx+2F8]
00485746 E8 C13CFBFF call 0043940C
0048574B 8B55 E0 mov edx, dword ptr [ebp-20]
0048574E 58 pop eax
0048574F E8 6CEAF7FF call 004041C0
00485754 8B55 E4 mov edx, dword ptr [ebp-1C]
00485757 58 pop eax
00485758 E8 A7EBF7FF call 00404304 ; 关键call
0048575D 75 59 jnz short 004857B8 ; 跳框
0048575F 6A 40 push 40
有3处跳转
……
004856C8 0F84 EA000000 je 004857B8
……
00485708 0F85 AA000000 jnz 004857B8
……
0048575D 75 59 jnz short 004857B8
……
是跳转到跳框部分代码,暴破把3处跳转屏蔽就可以了……
再看看这个CM的算法,在几处跳转前的call用OD跟进去分析
004856BE 8B45 FC mov eax, dword ptr [ebp-4]
004856C1 E8 02F9FFFF call 00484FC8
两处是用户名处理和检查用户名最后一位是否为大小定字母(B-Y和b-y),如果不符合,在
004856C8 0F84 EA000000 je 004857B8
处跳
004856DD E8 D2FCFFFF call 004853B4
处是按pixcel比较程序2处RGB值,并按是否相同(相同置0,不同置1)拼成串,并在
00485703 E8 FCEBF7FF call 00404304
处与注册码比较,不相等就跳
00485722 E8 E9EFFFFF call 00484710
处是处理注册码,并在
00485758 E8 A7EBF7FF call 00404304
处与用户名+序列号进行比较,不相等就跳
由于程序是delphi写的, 使用了大量的delphi封装、结构和函数调用,用OD分析,要跟入几层call的才搞清楚原来是delphi的封装,浪费大量时间。
所以用IDA进行静态分析,并载入dede产生的map,使用idc进行delphi结构扫描,分析过程略过,下面是关键代码和分析过程中写的注释
Tfrmmain_0_Formcreate分析
……
CODE:004859CC mov ebx, eax
CODE:004859CE mov edi, offset dword_488D08 ; 488D08->edi
CODE:004859D3 xor eax, eax
CODE:004859D5 push ebp
……
CODE:00485AAB mov eax, Timage_0_VmtPtr
CODE:00485AB0 call _PROC_0042DB20 ; TCustomPanel._PROC_0042DB20();创建Tpicture
CODE:00485AB5 mov [edi], eax ; 句柄写入488D08
CODE:00485AB7 mov edx, ebx
CODE:00485AB9 mov eax, [edi]
CODE:00485ABB mov ecx, [eax]
CODE:00485ABD call dword ptr [ecx+68h]
CODE:00485AC0 xor edx, edx
CODE:00485AC2 mov eax, [edi]
CODE:00485AC4 call TControl_SetLeft ; Controls.TControl.SetLeft(TControl;Integer);
CODE:00485AC9 mov edx, -10h
CODE:00485ACE mov eax, [edi]
CODE:00485AD0 call TControl_SetTop ; Controls.TControl.SetTop(TControl;Integer);
CODE:00485AD5 mov edx, 157h
CODE:00485ADA mov eax, [edi]
CODE:00485ADC call TControl_SetWidth ; Controls.TControl.SetWidth(TControl;Integer);
CODE:00485AE1 mov edx, 60h
CODE:00485AE6 mov eax, [edi]
CODE:00485AE8 call TControl_SetHeight ; Controls.TControl.SetHeight(TControl;Integer);
CODE:00485AED mov eax, [edi]
CODE:00485AEF call TControl_SendToBack ; Controls.TControl.SendToBack(TControl);
CODE:00485AF4 mov eax, offset a3w_bmp ; "3w.bmp"
CODE:00485AF9 call FileExists ; SysUtils.FileExists(AnsiString):Boolean;检查文件是否存在
CODE:00485AFE test al, al
CODE:00485B00 jz short loc_485B14
CODE:00485B02 mov eax, [edi]
CODE:00485B04 mov eax, [eax+168h]
CODE:00485B0A mov edx, offset a3w_bmp ; "3w.bmp"
CODE:00485B0F call TPicture_LoadFromFile ; Graphics.TPicture.LoadFromFile(TPicture;AnsiString);3w.bmp文件Load入Tpicture
……
这部分的的功能是在建立窗口时,新建Tpicture,并从3w.bmp载入
Tfrmmain_0_Btnokclick 分析
……
CODE:004856B0 lea edx, [ebp+var_4]
CODE:004856B3 mov eax, [ebx+2FCh] ; Edit_Name:TEdit
CODE:004856B9 call TControl_GetText ; Controls.TControl.GetText(TControl):TCaption;
CODE:004856BE mov eax, [ebp+var_4] ; edit_name值
CODE:004856C1 call sub_484FC8 ; 检查name值是否为空,最后一位是否字母
CODE:004856C6 test al, al ; 最后一位不是字母跳出
CODE:004856C8 jz loc_4857B8
CODE:004856CE lea ecx, [ebp+var_C]
CODE:004856D1 mov edx, ds:dword_488D08
CODE:004856D7 mov eax, [ebx+318h] ; Image1:TImage
CODE:004856DD call sub_4853B4 ; 将image1和488D08处指向的3w.bmp进行运算
CODE:004856E2 mov eax, [ebp+var_C] ; 将上个call产生string指针->EAX
CODE:004856E5 lea edx, [ebp+var_8] ; 将var地址->edx做为接收地址
CODE:004856E8 call Trim ; SysUtils.Trim(AnsiString):AnsiString;overload;
CODE:004856ED mov eax, [ebp+var_8]
CODE:004856F0 push eax ; 处理后的string指针入栈
CODE:004856F1 lea edx, [ebp+var_10]
CODE:004856F4 mov eax, [ebx+304h] ; Edit_Code:TEdit
CODE:004856FA call TControl_GetText ; Controls.TControl.GetText(TControl):TCaption;
CODE:004856FF mov edx, [ebp+var_10] ; edit_code值
CODE:00485702 pop eax
CODE:00485703 call System_@LStrCmp ; System.@LStrCmp;
CODE:00485708 jnz loc_4857B8 ; 比较code和string值,不符合跳出
CODE:0048570E lea edx, [ebp+var_18]
CODE:00485711 mov eax, [ebx+304h] ; Edit_Code:TEdit
CODE:00485717 call TControl_GetText ; Controls.TControl.GetText(TControl):TCaption;
CODE:0048571C mov eax, [ebp+var_18] ; 取code值
CODE:0048571F lea edx, [ebp+var_14]
CODE:00485722 call sub_484710 ; code处理
CODE:00485727 mov eax, [ebp+var_14] ; var_14为运算结果
CODE:0048572A push eax
CODE:0048572B lea edx, [ebp+var_1C]
CODE:0048572E mov eax, [ebx+2FCh] ; Edit_Name:TEdit
CODE:00485734 call TControl_GetText ; Controls.TControl.GetText(TControl):TCaption;
CODE:00485739 lea eax, [ebp+var_1C] ; 取name
CODE:0048573C push eax
CODE:0048573D lea edx, [ebp+var_20]
CODE:00485740 mov eax, [ebx+2F8h] ; Edit_ID:TEdit
CODE:00485746 call TControl_GetText ; Controls.TControl.GetText(TControl):TCaption;
CODE:0048574B mov edx, [ebp+var_20] ; 取ID
CODE:0048574E pop eax
CODE:0048574F call System_@LStrCat ; System.@LStrCat;
CODE:00485754 mov edx, [ebp+var_1C] ; name+ID
CODE:00485757 pop eax
CODE:00485758 call System_@LStrCmp ; System.@LStrCmp;比较code运算结果和name+id
CODE:0048575D jnz short loc_4857B8
……
这部分是注册码验证的主体部分,功能是:
1.校验用户名
2.将3w.bmp按象素与BMP1比较,并产生一个字串,字串再与注册码比较
3.注册码运算后与用户名与序列号连接后产生的字符串比较
call sub_484FC8 处用户名检查分析
……
CODE:00484FE9 mov eax, [ebp+var_4] ; 取name
CODE:00484FEC call sub_4041B8 ; 取name长度
CODE:00484FF1 mov esi, eax
CODE:00484FF3 cmp esi, 1
CODE:00484FF6 jge short loc_484FFD
CODE:00484FF8 call @Sysutils@Abort$qqrv ; Sysutils::Abort(void)
CODE:00484FFD
CODE:00484FFD loc_484FFD: ; CODE XREF: sub_484FC8+2Ej
CODE:00484FFD mov eax, esi
CODE:00484FFF test eax, eax
CODE:00485001 jl short loc_485027
CODE:00485003 inc eax
CODE:00485004 xor edx, edx ; byte指针初始化
CODE:00485006
CODE:00485006 loc_485006: ; CODE XREF: sub_484FC8+5Dj
CODE:00485006 mov ecx, [ebp+var_4] ; 取name
CODE:00485009 mov cl, [ecx+edx-1] ; 取一个byte
CODE:0048500D add cl, 0BEh ; -0xBE=0x42(B)
CODE:00485010 sub cl, 18h ; 0x18=24
CODE:00485013 jb short loc_485021 ; 在0x42-0x59间(B-Y),bl置1
CODE:00485015 add cl, 0F8h ; -0xF8+0x18-0xbe=0x62(b)
CODE:00485018 sub cl, 18h
CODE:0048501B jb short loc_485021 ; 在0x62-0x79间(b-y),bl置1
CODE:0048501D xor ebx, ebx
CODE:0048501F jmp short loc_485023 ; byte指针加1
CODE:00485021 ; ---------------------------------------------------------------------------
CODE:00485021
CODE:00485021 loc_485021: ; CODE XREF: sub_484FC8+4Bj
CODE:00485021 ; sub_484FC8+53j
CODE:00485021 mov bl, 1
CODE:00485023
CODE:00485023 loc_485023: ; CODE XREF: sub_484FC8+57j
CODE:00485023 inc edx ; byte指针加1
CODE:00485024 dec eax ; 循环指针-1
CODE:00485025 jnz short loc_485006 ; 取name
……
这部分是用户名校验过程
call sub_4853B4处picture比较分析
……
CODE:004853E3 mov [ebp+var_11], 0 ; 初始化var_11
CODE:004853E7 mov eax, [ebp+var_4] ; var_4为原EAX值
CODE:004853EA mov eax, [eax+168h]
CODE:004853F0 call TPicture_GetBitmap ; BDS 2005-2006 and Delphi6-7 Visual Component Library
CODE:004853F5 mov edx, [eax] ; EAX指向tbitmap
CODE:004853F7 call dword ptr [edx+20h] ; Graphics::TBitmap::GetHeight(void)
CODE:004853FA dec eax ; EAX=BitMap高度
CODE:004853FB test eax, eax
CODE:004853FD jl loc_4854AC
CODE:00485403 inc eax
CODE:00485404 mov [ebp+var_18], eax
CODE:00485407 mov [ebp+var_10], 0
CODE:0048540E
CODE:0048540E loc_48540E: ; CODE XREF: sub_4853B4+F2j
CODE:0048540E mov eax, [ebp+var_4]
CODE:00485411 mov eax, [eax+168h]
CODE:00485417 call TPicture_GetBitmap ; BDS 2005-2006 and Delphi6-7 Visual Component Library
CODE:0048541C mov edx, [eax]
CODE:0048541E call dword ptr [edx+2Ch] ; Graphics::TBitmap::GetWidth(void)
CODE:00485421 dec eax ; EAX=BitMap宽度
CODE:00485422 test eax, eax
CODE:00485424 jl short loc_4854A0 ; y++
CODE:00485426 inc eax
CODE:00485427 mov [ebp+var_1C], eax
CODE:0048542A xor esi, esi
CODE:0048542C
CODE:0048542C loc_48542C: ; CODE XREF: sub_4853B4+EAj
CODE:0048542C mov eax, [ebp+var_4] ; var_4为原EAX值
CODE:0048542F mov eax, [eax+168h]
CODE:00485435 call TPicture_GetBitmap ; BDS 2005-2006 and Delphi6-7 Visual Component Library
CODE:0048543A call @Graphics@TBitmap@GetCanvas$qqrv ; Graphics::TBitmap::GetCanvas(void)
CODE:0048543F mov ecx, [ebp+var_10] ; X值
CODE:00485442 mov edx, esi ; Y值
CODE:00485444 call @Graphics@TCanvas@GetPixel$qqrii ; Graphics::TCanvas::GetPixel(int,int)
CODE:00485449 mov edi, eax ; pixel的RGB值放入EDI
CODE:0048544B mov eax, [ebp+var_8] ; var_8为原EDX值
CODE:0048544E mov eax, [eax+168h]
CODE:00485454 call TPicture_GetBitmap ; BDS 2005-2006 and Delphi6-7 Visual Component Library
CODE:00485459 call @Graphics@TBitmap@GetCanvas$qqrv ; Graphics::TBitmap::GetCanvas(void)
CODE:0048545E mov ecx, [ebp+var_10] ; X值
CODE:00485461 mov edx, esi ; Y值
CODE:00485463 call @Graphics@TCanvas@GetPixel$qqrii ; Graphics::TCanvas::GetPixel(int,int)
CODE:00485468 cmp edi, eax
CODE:0048546A jz short loc_48546F
CODE:0048546C or [ebp+var_11], bl ; 比较两组RGB值,相同处置var_11相应位为0,不同处置相应位为1
CODE:0048546F
CODE:0048546F loc_48546F: ; CODE XREF: sub_4853B4+B6j
CODE:0048546F xor eax, eax
CODE:00485471 mov al, bl
CODE:00485473 shr eax, 1 ; 初始值80,每次右移1位,8次跳出,bit->byte
CODE:00485475 mov ebx, eax
CODE:00485477 test bl, bl
CODE:00485479 jnz short loc_48549A ; x++
CODE:0048547B lea eax, [ebp+var_20]
CODE:0048547E mov dl, [ebp+var_11]
CODE:00485481 call unknown_libname_67 ; 把var_11转化为string,返回指针
CODE:00485486 mov edx, [ebp+var_20] ; 把string返回指针放入EDX
CODE:00485489 mov eax, [ebp+var_C] ; 原ECX值
CODE:0048548C call System_@LStrCat ; var_11转换值放入var_c指针指向的字符串尾
CODE:00485491 mov eax, [ebp+var_C]
CODE:00485494 mov bl, 80h ; 初始化bl
CODE:00485496 mov [ebp+var_11], 0 ; 初始化var_11
CODE:0048549A
CODE:0048549A loc_48549A: ; CODE XREF: sub_4853B4+C5j
CODE:0048549A inc esi ; x++
CODE:0048549B dec [ebp+var_1C] ; 高度指针-1
CODE:0048549E jnz short loc_48542C ; 高度指针指向0跳出
CODE:004854A0
CODE:004854A0 loc_4854A0: ; CODE XREF: sub_4853B4+70j
CODE:004854A0 inc [ebp+var_10] ; y++
CODE:004854A3 dec [ebp+var_18] ; 宽度指针-1
CODE:004854A6 jnz loc_48540E ; 宽度指针指向0跳出
……
这部分是3w.bmp与BMP1比较产生字符串的过程
call sub_484710处注册码处理分析
……
CODE:00484723 mov esi, edx ; 指针放入esi
CODE:00484725 mov [ebp+var_4], eax ; code值地址放入var_4
CODE:00484728 mov eax, [ebp+var_4]
CODE:0048472B call @System@@LStrAddRef$qqrpv ; System::__linkproc__ LStrAddRef(void *)
CODE:00484730 mov ebx, offset aAbcdefghijklmn ; 引入字符表A,字符表地址放入ebx
CODE:00484735 xor eax, eax
……
CODE:00484747 jz loc_48496E ; code为空跳出
CODE:0048474D lea eax, [ebp+var_10]
CODE:00484750 mov dl, [ebx+29h]
CODE:00484753 mov [eax+1], dl
CODE:00484756 mov byte ptr [eax], 1 ; var_10低位=1 高位=字符表+29h(O)
CODE:00484759 lea edx, [ebp+var_10]
CODE:0048475C lea eax, [ebp+var_14]
CODE:0048475F call @System@@PStrCpy$qqrp28System@_SmallString$iuc$255_t1 ; System::__linkproc__ PStrCpy(System::SmallString<(uchar)255> *,System::SmallString<(uchar)255> *)
CODE:00484764 lea eax, [ebp+var_18]
CODE:00484767 mov dl, [ebx+2]
CODE:0048476A mov [eax+1], dl
CODE:0048476D mov byte ptr [eax], 1 ; var_18低位=1,高位=字符表+2h(b)
……
CODE:0048493B lea eax, [ebp+var_9C]
CODE:00484941 mov cl, 0Eh
CODE:00484943 call @System@@PStrNCat$qqrv ; System::__linkproc__ PStrNCat(void)
CODE:00484948 lea edx, [ebp+var_9C] ; var_9c=0E4F626A656374466F725A312E3021h(ObjectForZ1.0!)
CODE:0048494E lea eax, [ebp+var_8]
CODE:00484951 call unknown_libname_70 ; BDS 2005-2006 and Delphi6-7 Visual Component Library
CODE:00484956 lea edx, [ebp+var_C] ; 处理后的字符表A为ObjectForZ1.0!,string(ObjectForZ1.0!)地址->var_8
CODE:00484959 mov eax, [ebp+var_4] ; 取Code
CODE:0048495C call sub_484420 ; code处理
CODE:00484961 mov ecx, esi ; 指针
CODE:00484963 mov edx, [ebp+var_8] ; 处理后的字符表A指针
CODE:00484966 mov eax, [ebp+var_C] ; 处理后的code指针
CODE:00484969 call sub_484578 ; 再加入2个字符表,运算后再分为两个0xA长度的表并根据处理后code的长度进行运算
……
这部分的功能是对注册码进行运算,具体分为:
1.由字符表A产生字符串“ObjectForZ1.0!”
2.引入一个长度为64的字符串“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=”对注册码进行第一次处理
3.由1和2产的字符串,再引入2张字符表, 进行运算,得到最终结果
call sub_484420处注册码第一次处理分析,引入长度为0x3F(63)的字符表B
……
CODE:00484477 mov eax, edi ; code分成4个byte一组处理
CODE:00484479 shl eax, 2
CODE:0048447C inc eax ; edi*4+1
CODE:0048447D mov edx, [ebp+var_4] ; edx=code地址
CODE:00484480 mov al, [edx+eax-1] ; 取edi*4位
CODE:00484484 call sub_4843CC ; 取在字母表中位置
CODE:00484489 mov [ebp+var_5], al ; var_5=第1个字符在字母表中位置
CODE:0048448C mov eax, edi
CODE:0048448E shl eax, 2
CODE:00484491 add eax, 2 ; edi*4+2
CODE:00484494 mov edx, [ebp-4] ; 取code
CODE:00484497 mov al, [edx+eax-1] ; 取edi*4+1位
CODE:0048449B call sub_4843CC ; 取在字母表中位置
CODE:004844A0 mov [ebp+var_6], al ; var_6=第2个字符在字母表中位置
CODE:004844A3 mov eax, edi
CODE:004844A5 shl eax, 2
CODE:004844A8 add eax, 3
CODE:004844AB mov edx, [ebp+var_4]
CODE:004844AE mov al, [edx+eax-1]
CODE:004844B2 call sub_4843CC ; 取在字母表中位置
CODE:004844B7 mov ebx, eax ; ebx=第3个字符在字母表中位置
CODE:004844B9 mov eax, edi
CODE:004844BB shl eax, 2
CODE:004844BE add eax, 4
CODE:004844C1 mov edx, [ebp+var_4]
CODE:004844C4 mov al, [edx+eax-1]
CODE:004844C8 call sub_4843CC ; 取在字母表中位置
CODE:004844CD mov [ebp+var_7], al ; var_7=第4个字符在字母表中位置
CODE:004844D0 shl [ebp+var_5], 2 ; var_5<<2
CODE:004844D4 xor eax, eax
CODE:004844D6 mov al, [ebp+var_6]
CODE:004844D9 shr eax, 4
CODE:004844DC or [ebp+var_5], al ; var_5<<2|var_6>>4
CODE:004844DF shl [ebp+var_6], 4 ; var_6<<4
CODE:004844E3 lea eax, [ebp+var_10]
CODE:004844E6 mov dl, [ebp+var_5] ; 计算后,第2-7位为第1字符在字符表中索引,第0-1位为第2字符在字符表中索引的4-5位
CODE:004844E9 call unknown_libname_67 ; string()
CODE:004844EE mov edx, [ebp+var_10]
CODE:004844F1 mov eax, esi
CODE:004844F3 call System_@LStrCat ; var_10填入esi指向的string
CODE:004844F8 cmp bl, 40h
CODE:004844FB jz short loc_484546 ; bl=40h跳出
CODE:004844FD xor eax, eax
CODE:004844FF mov al, bl
CODE:00484501 shr eax, 2
CODE:00484504 or [ebp+var_6], al ; var_6|bl>>2
CODE:00484507 shl bl, 6 ; bl<<6
CODE:0048450A lea eax, [ebp+var_14]
CODE:0048450D mov dl, [ebp+var_6] ; 计算后,第4-7位为第2字符在字符表中索引的0-3位,第0-3位为第3字符在字符表中索引的2-5位
CODE:00484510 call unknown_libname_67 ; string()
CODE:00484515 mov edx, [ebp+var_14]
CODE:00484518 mov eax, esi
CODE:0048451A call System_@LStrCat ; var_14->esi指向的string
CODE:0048451F cmp [ebp+var_7], 40h
CODE:00484523 jz short loc_484546 ; var_7=40跳出
CODE:00484525 or bl, [ebp+var_7] ; bl<<6|var_7
CODE:00484528 lea eax, [ebp+var_18]
CODE:0048452B mov edx, ebx ; 计算后,第6-7位为第3字符在字符表中索引的0-1位,第0-5位为第4字符在字符表中索引
CODE:0048452D call unknown_libname_67 ; string()
CODE:00484532 mov edx, [ebp+var_18]
CODE:00484535 mov eax, esi
CODE:00484537 call System_@LStrCat ; var_18->esi指向的string
CODE:0048453C inc edi ; edi++
CODE:0048453D dec [ebp+var_C] ; 计数指针--
CODE:00484540 jnz loc_484477 ; code分成4个byte一组处理
……
这部分是把注册码(code)按4个字节分成段,引入一个64字节长的字串“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=”(code3),每段按字节在字串中的索引组成1个3字节长的串,最终形成一个长度为注册码长度3/4的串key。C的等同算法:
len=strlen(code);
for (i=0,i<len,i=i+4)
{
key[i/4*3]=(strchr(code3,code[i])-code3)<<2|(strchr(code3,code[i+1])-code3)>>4;
key[i/4*3+1]=(strchr(code3,code[i+1])-code3)<<4|(strchr(code3,code[i+2])-code3)>>2;
key[i/4*3+2]=(strchr(code3,code[i+2])-code3)<<6|(strchar(code3,code[i+3])-code3);
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)