在分析之前,先整理一下程序流程。整个流程可以分解为以下几步:
破解一般是从第3步或第5步进行。因为从文本框获取信息无非就是几个函数GetWindowText, GetDlgItemText, CWnd::GetWindowText
。而显示校验结果的也无非是几个函数,SetWindowText, SetDlgItemText, CWnd::SetWindowText, CWnd::SetDlgItemText,MessageBox, DoModal
等,当然校验结果的信息也可以通过搜索内存来达到。
一般情况下,先从第5点开始分析,因为通过栈回溯一般很容易找到关键的校验点。
重新启动SCRT
程序,
选择“Enter License Data”
,出现
用windbg
附加到进程里。这个进程名称叫licenseHelper
由于这个程序并不会弹出对话框,所以,MessageBox, DoModal
之类的函数不用关注,只要看一下SetWindowText, SetDlgItemText, CWnd::SetWindowText, CWnd::SetDlgItemText
.
搜索一下SetWindowText, SetDlgItemText, CWnd::SetWindowText, CWnd::SetDlgItemText
这些符号
由于SetWindowText, SetDlgItemText
是在user32.dll
定义的, CWnd
这个类是MFC库定义, 且windows
默认是unicode
编码,SetWindowTextA
调用SetWindowTextW
, SetDlgItemTextA
调用SetDlgItemTextW
同时CWnd::SetWindowTextW
是调用SetWindowTextW
,CWnd::SetDlgItemTextW
是调用SetDlgItemTextW
,所以在这里选取在
77d2960e USER32!SetWindowTextW = <no type information>
77d2736c USER32!SetDlgItemTextW = <no type information>
打断点
运行结果如下:
0:000> g
Breakpoint 0 hit eax=00000001 ebx=2001f958 ecx=77d2934b edx=7c92e401 esi=00aa0f78 edi=003fe1d4
eip=77d2960e esp=0012ef1c ebp=0012ef2c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
USER32!SetWindowTextW:
77d2960e 8bff mov edi,edi
0:000> kb
ChildEBP RetAddr Args to Child
0012ef18 7884a04e 0002042e 2001f958 003fe108 USER32!SetWindowTextW
0012ef2c 200073de 2001f958 003fe1d4 0012efb4 mfc100u!CWnd::SetWindowTextW+0x42
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ef44 2000418d ffffff00 2001f958 20007cb0 LicenseUI70U!ShowInvalidLicenseDialog+0x169e
0012ef7c 787df50d 003fe240 0000004e 00159670 LicenseUI70U+0x418d
0012ef90 78834c72 00000000 0012f338 0012efb4 mfc100u!CPropertyPage::OnNotify+0xe9
0012f058 78834bad 0000004e 00000000 0012f338 mfc100u!CWnd::OnWndMsg+0x9e
0012f078 78832fcc 0000004e 00000000 0012f338 mfc100u!CWnd::WindowProc+0x24
0012f0f0 78833258 003fe240 00020420 0000004e mfc100u!AfxCallWndProc+0xb5
0012f114 78729faf 00020420 0000004e 00000000 mfc100u!AfxWndProc+0x37
0012f158 77d18734 00020420 0000004e 00000000 mfc100u!AfxWndProcBase+0x56
0012f184 77d18816 78729f59 00020420 0000004e USER32!InternalCallWinProc+0x28
0012f1ec 77d2927b 0015c3b0 78729f59 00020420 USER32!UserCallWinProcCheckWow+0x150
0012f228 77d292e3 00743160 006f77a8 00000000 USER32!SendMessageWorker+0x4a5
0012f248 7719ab34 00020420 0000004e 00000000 USER32!SendMessageW+0x7f
0012f2e0 7719b17c 0012f2f8 ffffff31 0012f338 COMCTL32!CCSendNotify+0x748
0012f31c 771887d9 00020420 000a02a4 ffffff31 COMCTL32!SendNotifyEx+0x57
0012f348 7718a55f 0015f210 00000000 ffffff31 COMCTL32!_Ppd_SendNotify+0x2b
0012f368 7718c154 0015f210 ffffff31 00003024 COMCTL32!WizNextBack+0x2a
0012f384 7718c67b 0015f210 00003024 0002043a COMCTL32!Prsht_OnCommand+0x14f
0012f3fc 77d18734 000a02a4 00000111 00003024 COMCTL32!PropSheetDlgProc+0x4b1
0:000> du 2001f958
2001f958 "&Extend Evaluation"
0:000> g
Breakpoint 0 hit eax=00000001 ebx=2001f928 ecx=77d2934b edx=7c92e401 esi=00aa0f78 edi=003fe1d4
eip=77d2960e esp=0012ece8 ebp=0012ecf8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
USER32!SetWindowTextW:
77d2960e 8bff mov edi,edi
0:000> kb
ChildEBP RetAddr Args to Child
0012ece4 7884a04e 0002042e 2001f928 003fe108 USER32!SetWindowTextW
0012ecf8 200073de 2001f928 003fe35c 003fe1d4 mfc100u!CWnd::SetWindowTextW+0x42
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ed10 2000419d 7c92e401 2001f928 20007ed4 LicenseUI70U!ShowInvalidLicenseDialog+0x169e
0012ed44 787df4b6 003fe35c 0000004e 00159670 LicenseUI70U+0x419d
0012ed58 78834c72 00000000 0012f100 0012ed7c mfc100u!CPropertyPage::OnNotify+0x92
0012ee20 78834bad 0000004e 00000000 0012f100 mfc100u!CWnd::OnWndMsg+0x9e
0012ee40 78832fcc 0000004e 00000000 0012f100 mfc100u!CWnd::WindowProc+0x24
0012eeb8 78833258 003fe35c 001e06f8 0000004e mfc100u!AfxCallWndProc+0xb5
0012eedc 78729faf 001e06f8 0000004e 00000000 mfc100u!AfxWndProc+0x37
0012ef20 77d18734 001e06f8 0000004e 00000000 mfc100u!AfxWndProcBase+0x56
0012ef4c 77d18816 78729f59 001e06f8 0000004e USER32!InternalCallWinProc+0x28
0012efb4 77d2927b 0015c3b0 78729f59 001e06f8 USER32!UserCallWinProcCheckWow+0x150
0012eff0 77d292e3 0074f900 006f77a8 00000000 USER32!SendMessageWorker+0x4a5
0012f010 7719ab34 001e06f8 0000004e 00000000 USER32!SendMessageW+0x7f
0012f0a8 7719b17c 0012f0c0 ffffff38 0012f100 COMCTL32!CCSendNotify+0x748
0012f0e4 771887d9 001e06f8 000a02a4 ffffff38 COMCTL32!SendNotifyEx+0x57
0012f110 7718a17c 0015f210 00000001 ffffff38 COMCTL32!_Ppd_SendNotify+0x2b
0012f32c 7718a526 0015f210 00000001 0015f210 COMCTL32!PageChange+0x2e7
0012f348 7718a582 0015f210 00000000 00000001 COMCTL32!PageSetSelection+0x95
0012f368 7718c154 0015f210 ffffff31 00003024 COMCTL32!WizNextBack+0x4d
0:000> du 2001f928
2001f928 "&Enter License Manually"
0:000> g
(efc.588): C++ EH exception - code e06d7363 (first chance)
Breakpoint 0 hit
eax=00000001 ebx=00aa15b4 ecx=77d2934b edx=00aa0901 esi=003fc6d8 edi=00000000
eip=77d2960e esp=0012ed08 ebp=0012ed18 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
USER32!SetWindowTextW:
77d2960e 8bff mov edi,edi
0:000> kb
ChildEBP RetAddr Args to Child
0012ed04 7884a04e 0003070a 00aa15b4 003fe35c USER32!SetWindowTextW
0012ed18 20007f77 00aa15b4 b20107b6 0012f100 mfc100u!CWnd::SetWindowTextW+0x42
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ed44 787df4b6 003fe35c 0000004e 00159670 LicenseUI70U!ShowLicenseWizard+0xa27
0012ed58 78834c72 00000000 0012f100 0012ed7c mfc100u!CPropertyPage::OnNotify+0x92
0012ee20 78834bad 0000004e 00000000 0012f100 mfc100u!CWnd::OnWndMsg+0x9e
0012ee40 78832fcc 0000004e 00000000 0012f100 mfc100u!CWnd::WindowProc+0x24
0012eeb8 78833258 003fe35c 001e06f8 0000004e mfc100u!AfxCallWndProc+0xb5
0012eedc 78729faf 001e06f8 0000004e 00000000 mfc100u!AfxWndProc+0x37
0012ef20 77d18734 001e06f8 0000004e 00000000 mfc100u!AfxWndProcBase+0x56
0012ef4c 77d18816 78729f59 001e06f8 0000004e USER32!InternalCallWinProc+0x28
0012efb4 77d2927b 0015c3b0 78729f59 001e06f8 USER32!UserCallWinProcCheckWow+0x150
0012eff0 77d292e3 0074f900 006f77a8 00000000 USER32!SendMessageWorker+0x4a5
0012f010 7719ab34 001e06f8 0000004e 00000000 USER32!SendMessageW+0x7f
0012f0a8 7719b17c 0012f0c0 ffffff38 0012f100 COMCTL32!CCSendNotify+0x748
0012f0e4 771887d9 001e06f8 000a02a4 ffffff38 COMCTL32!SendNotifyEx+0x57
0012f110 7718a17c 0015f210 00000001 ffffff38 COMCTL32!_Ppd_SendNotify+0x2b
0012f32c 7718a526 0015f210 00000001 0015f210 COMCTL32!PageChange+0x2e7
0012f348 7718a582 0015f210 00000000 00000001 COMCTL32!PageSetSelection+0x95
0012f368 7718c154 0015f210 ffffff31 00003024 COMCTL32!WizNextBack+0x4d
0012f384 7718c67b 0015f210 00003024 0002043a COMCTL32!Prsht_OnCommand+0x14f
0:000> du 00aa15b4
00aa15b4 "The license data was not valid.."
00aa15f4 "...Press the Back button to try "
00aa1634 "again or press the Enter License"
00aa1674 " Manually button to enter the li"
00aa16b4 "cense data by hand..."
0:000> g
Breakpoint 0 hit
eax=0012f1c4 ebx=77d2af56 ecx=0012f0d8 edx=7c92e4f4 esi=0015f210 edi=77d2929a
eip=77d2960e esp=0012f11c ebp=0012f32c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
USER32!SetWindowTextW:
77d2960e 8bff mov edi,edi
0:000> kb
ChildEBP RetAddr Args to Child
0012f118 7718a331 000a02a4 0012f1c4 0015f210 USER32!SetWindowTextW
0012f32c 7718a526 0015f210 00000001 0015f210 COMCTL32!PageChange+0x49c
0012f348 7718a582 0015f210 00000000 00000001 COMCTL32!PageSetSelection+0x95
0012f368 7718c154 0015f210 ffffff31 00003024 COMCTL32!WizNextBack+0x4d
0012f384 7718c67b 0015f210 00003024 0002043a COMCTL32!Prsht_OnCommand+0x14f
0012f3fc 77d18734 000a02a4 00000111 00003024 COMCTL32!PropSheetDlgProc+0x4b1
0012f428 77d23ce4 7718c1ca 000a02a4 00000111 USER32!InternalCallWinProc+0x28
0012f494 77d23b30 001592a0 7718c1ca 000a02a4 USER32!UserCallDlgProcCheckWow+0x146
0012f4dc 77d23d5c 00000000 00000111 00003024 USER32!DefDlgProcWorker+0xa8
0012f4f8 77d18734 000a02a4 00000111 00003024 USER32!DefDlgProcW+0x22
0012f524 77d18816 77d23d3a 000a02a4 00000111 USER32!InternalCallWinProc+0x28
0012f58c 77d2a013 001592a0 77d23d3a 000a02a4 USER32!UserCallWinProcCheckWow+0x150
0012f5bc 77d2a039 77d23d3a 000a02a4 00000111 USER32!CallWindowProcAorW+0x98
0012f5dc 78833b50 77d23d3a 000a02a4 00000111 USER32!CallWindowProcW+0x1b
0012f5fc 78834bc4 00000111 00003024 0002043a mfc100u!CWnd::DefWindowProcW+0x44
0012f618 78832fcc 00000111 00003024 0002043a mfc100u!CWnd::WindowProc+0x3b
0012f690 78833258 003fe108 000a02a4 00000111 mfc100u!AfxCallWndProc+0xb5
0012f6b4 78729faf 000a02a4 00000111 00003024 mfc100u!AfxWndProc+0x37
0012f6f8 77d18734 000a02a4 00000111 00003024 mfc100u!AfxWndProcBase+0x56
0012f724 77d18816 78729f59 000a02a4 00000111 USER32!InternalCallWinProc+0x28
0:000> du 0012f1c4
0012f1c4 "License Wizard"
可以看到出错界面显示的字符串都在上面。
由于堆栈
0012ed04 7884a04e 0003070a 00aa15b4 003fe35c USER32!SetWindowTextW
0012ed18 20007f77 00aa15b4 b20107b6 0012f100 mfc100u!CWnd::SetWindowTextW+0x42
WARNING: Stack unwind information not available. Following frames may be wrong.
0012ed44 787df4b6 003fe35c 0000004e 00159670 LicenseUI70U!ShowLicenseWizard+0xa27
0012ed58 78834c72 00000000 0012f100 0012ed7c mfc100u!CPropertyPage::OnNotify+0x92
才是显示那出错信息的。
所以,看一下返回地址20007f77所指向的函数是怎样
.text:20007F53 lea edx, [ebp+var_10]
.text:20007F56 push edx
.text:20007F57 mov ecx, ebx
.text:20007F59 call sub_20002890
.text:20007F5E mov ebx, [ebp+var_10]
.text:20007F61 push ebx
.text:20007F62 push 7EFh
.text:20007F67 mov ecx, esi ; this pointer
.text:20007F69 call ds:mfc100u_4805 ; CWnd::GetDlgItem
.text:20007F6F mov ecx, eax ; ecx store this pointer
.text:20007F71 call ds:mfc100u_12951 ; CWnd::SetWindowTextW
.text:20007F77 mov ecx, esi
根据CWnd::GetDlgItem
和CWnd::SetWindowTextW
的原型:
CWnd* GetDlgItem( int nID ) const;
void SetWindowText( LPCTSTR lpszString );
可知,ebx应该是lpszString
的指针。在20007F71打断点:
0:001> bp 20007F71
0:001> g
(efc.588): C++ EH exception - code e06d7363 (first chance)
(efc.588): C++ EH exception - code e06d7363 (first chance)
Breakpoint 0 hit
eax=003fc6d8 ebx=00aa15b4 ecx=003fc6d8 edx=00aa095c esi=003fe35c edi=00000000
eip=20007f71 esp=0012ed20 ebp=0012ed44 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
LicenseUI70U!ShowLicenseWizard+0xa21:
20007f71 ff1578f20120 call dword ptr [LicenseUI70U!ShowOfferHelpDialog+0x12458 (2001f278)] ds:0023:2001f278={mfc100u!CWnd::SetWindowTextW (7884a00c)}
0:000> du ebx
00aa15b4 "The license data was not valid.."
00aa15f4 "...Press the Back button to try "
00aa1634 "again or press the Enter License"
00aa1674 " Manually button to enter the li"
00aa16b4 "cense data by hand..."
果然是由ebx传入的。而ebx是在这一系列中
.text:20007F53 lea edx, [ebp+var_10]
.text:20007F56 push edx
.text:20007F57 mov ecx, ebx
.text:20007F59 call sub_20002890
.text:20007F5E mov ebx, [ebp+var_10]
由sub_20002890
取出的值。而由
可知没有任何其它参数传入得到这个值,这个值是完全由20002890得出的。
而看一下整个函数
.text:20007E60 sub_20007E60 proc near ; DATA XREF: .rdata:20020E54o
.text:20007E60 .text:20007E60 var_10 = dword ptr -10h
.text:20007E60 var_C = dword ptr -0Ch
.text:20007E60 var_4 = dword ptr -4
.text:20007E60
.text:20007E60 push ebp
.text:20007E61 mov ebp, esp
.text:20007E63 push 0FFFFFFFFh
.text:20007E65 push offset [email protected]@[email protected]@@Z_20 .text:20007E6A mov eax, large fs:0
.text:20007E70 push eax
.text:20007E71 push ecx
.text:20007E72 push ebx
.text:20007E73 push esi
.text:20007E74 push edi
.text:20007E75 mov eax, dword_20038018
.text:20007E7A xor eax, ebp
.text:20007E7C push eax
.text:20007E7D lea eax, [ebp+var_C]
.text:20007E80 mov large fs:0, eax
.text:20007E86 mov esi, ecx
.text:20007E88 mov eax, [esi+20h]
.text:20007E8B push eax ; hWnd
.text:20007E8C call ds:GetParent
.text:20007E92 push eax
.text:20007E93 call ds:mfc100u_4360 ; CWnd::FromHandle
.text:20007E99 push 0
.text:20007E9B push offset off_20038208
.text:20007EA0 push offset off_2003805C
.text:20007EA5 push 0
.text:20007EA7 push eax
.text:20007EA8 call __RTDynamicCast
.text:20007EAD add esp, 14h
.text:20007EB0 push 1 ; lParam .
text:20007EB2 push 0 ; wParam
.text:20007EB4 mov edi, eax
.text:20007EB6 mov ecx, [edi+20h]
.text:20007EB9 push 470h ; Msg
.text:20007EBE push ecx ; hWnd
.text:20007EBF call ds:PostMessageW
.text:20007EC5 lea ebx, [edi+0CCh]
.text:20007ECB mov dl, 1
.text:20007ECD mov ecx, ebx
.text:20007ECF call sub_20004190
.text:20007ED4 mov eax, edi
.text:20007ED6 call sub_20007310
.text:20007EDB mov edx, [esi+0C8h]
.text:20007EE1 xor edi, edi
.text:20007EE3 push edi ; lParam
.text:20007EE4 push eax ; wParam
.text:20007EE5 push 170h ; Msg
.text:20007EEA push edx ; hWnd
.text:20007EEB call ds:SendMessageW
.text:20007EF1 test byte ptr dword_200405C8, 2
.text:20007EF8 jnz short loc_20007F3A
.text:20007EFA or dword_200405C8, 2
.text:20007F01 mov eax, 1
.text:20007F06 mov [ebp+var_4], eax
.text:20007F09 xor ecx, ecx
.text:20007F0B mov word_200405AC, cx
.text:20007F12 mov Addend, eax
.text:20007F17 mov dword_200405A4, edi
.text:20007F1D mov dword_2004059C, edi
.text:20007F23 mov dword_20040598, edi
.text:20007F29 mov dword_200405A0, offset word_200405AC
.text:20007F33 mov [ebp+var_4], 0FFFFFFFFh
.text:20007F3A
.text:20007F3A loc_20007F3A: ; CODE XREF: sub_20007E60+98j
.text:20007F3A push offset Addend ; lpAddend
.text:20007F3F call ds:InterlockedIncrement
.text:20007F45 mov [ebp+var_10], offset word_200405AC
.text:20007F4C mov [ebp+var_4], 2
.text:20007F53 lea edx, [ebp+var_10]
.text:20007F56 push edx
.text:20007F57 mov ecx, ebx
.text:20007F59 call sub_20002890
.text:20007F5E mov ebx, [ebp+var_10]
.text:20007F61 push ebx
.text:20007F62 push 7EFh
.text:20007F67 mov ecx, esi ; this pointer
.text:20007F69 call ds:mfc100u_4805 ; CWnd::GetDlgItem
.text:20007F6F mov ecx, eax ; ecx store this pointer
.text:20007F71 call ds:mfc100u_12951 ; CWnd::SetWindowTextW
.text:20007F77 mov ecx, esi
.text:20007F79 call ds:__imp_mfc100u_10352 ; CPropertyPage::OnSetActive
.text:20007F7F mov edi, eax
.text:20007F81 mov [ebp+var_4], 0FFFFFFFFh
.text:20007F88 lea esi, [ebx-14h]
.text:20007F8B lea eax, [esi+10h]
.text:20007F8E push eax ; lpAddend
.text:20007F8F call ds:InterlockedDecrement
.text:20007F95 test eax, eax
.text:20007F97 jg short loc_20007FB9
.text:20007F99 cmp dword ptr [esi+0Ch], 1
.text:20007F9D jnz short loc_20007FAF
.text:20007F9F mov ecx, [esi]
.text:20007FA1 add ecx, 14h
.text:20007FA4 mov eax, esi
.text:20007FA6 jz short loc_20007FAF
.text:20007FA8
.text:20007FA8 loc_20007FA8: ; CODE XREF: sub_20007E60+14Dj
.text:20007FA8 mov byte ptr [eax], 0
.text:20007FAB inc eax
.text:20007FAC dec ecx
.text:20007FAD jnz short loc_20007FA8
.text:20007FAF
.text:20007FAF loc_20007FAF: ; CODE XREF: sub_20007E60+13Dj
.text:20007FAF ; sub_20007E60+146j
.text:20007FAF push esi ; Memory
.text:20007FB0 call ds:free
.text:20007FB6 add esp, 4
.text:20007FB9
.text:20007FB9 loc_20007FB9: ; CODE XREF: sub_20007E60+137j
.text:20007FB9 mov eax, edi
.text:20007FBB mov ecx, [ebp+var_C]
.text:20007FBE mov large fs:0, ecx
.text:20007FC5 pop ecx
.text:20007FC6 pop edi
.text:20007FC7 pop esi
.text:20007FC8 pop ebx
.text:20007FC9 mov esp, ebp
.text:20007FCB pop ebp
.text:20007FCC retn
.text:20007FCC sub_20007E60 endp
虽然20007F3A这一跳转地址,但无论如何,函数都会执行到显示出“The license data was not valid”
的字符串。说明sub_20007E60
是位于license
校验失败的分支流程中。
由于调用sub_20007E60
的函数是MFC库的函数,所以,在这里,通过校验结果来破解是行不通的。
由于上面的分析失败,尝试一下通过GetWindowText, GetDlgItemText, CWnd::GetWindowText
等API来分析。
由于MFC
是对user32
的封装。所以只看GetWindowText, GetDlgItemText
结果一运行
0:001> g
Breakpoint 0 hit
eax=0015ee40 ebx=00168278 ecx=0000000a edx=00730001 esi=7c9300a4 edi=00000014
eip=77d2a5cd esp=0012f664 ebp=0012f74c iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
USER32!GetWindowTextW:
77d2a5cd 6a0c push 0Ch
0:000> kb
ChildEBP RetAddr Args to Child
0012f660 771a8566 0002043a 0015ee40 0000000a USER32!GetWindowTextW
0012f74c 771a88c5 00000000 ea011aa2 00000001 COMCTL32!Button_DrawThemed+0x262
0012f7c4 771a8e09 00000001 ea011aa2 00000001 COMCTL32!Button_DrawPush+0x44
0012f840 771a9130 00000001 ea011aa2 0012f938 COMCTL32!Button_Paint+0x2e6
0012f8d0 77d18734 0002043a 0000000f 00000000 COMCTL32!Button_WndProc+0x271
0012f8fc 77d18816 771a8ebf 0002043a 0000000f USER32!InternalCallWinProc+0x28
0012f964 77d2a013 001592a0 771a8ebf 0002043a USER32!UserCallWinProcCheckWow+0x150
0012f994 77d2a039 771a8ebf 0002043a 0000000f USER32!CallWindowProcAorW+0x98
0012f9b4 77191b72 771a8ebf 0002043a 0000000f USER32!CallWindowProcW+0x1b
0012f9d0 77191ec5 0002043a 0000000f 00000000 COMCTL32!CallOriginalWndProc+0x1a
0012fa2c 77192087 00168468 0002043a 0000000f COMCTL32!CallNextSubclassProc+0x3c
0012fa50 7718866f 0002043a 0000000f 00000000 COMCTL32!DefSubclassProc+0x46
0012fa6c 77191ec5 0002043a 0000000f 00000000 COMCTL32!Prsht_ButtonSubclassProc+0x69
0012fac8 771920ea 00168468 0002043a 0000000f COMCTL32!CallNextSubclassProc+0x3c
0012fb1c 77d18734 0002043a 0000000f 00000000 COMCTL32!MasterSubclassProc+0x54
0012fb48 77d18816 77192096 0002043a 0000000f USER32!InternalCallWinProc+0x28
0012fbb0 77d28ea0 001592a0 77192096 0002043a USER32!UserCallWinProcCheckWow+0x150
0012fc04 77d28eec 00744248 0000000f 00000000 USER32!DispatchClientMessage+0xa3
0012fc2c 7c92e453 0012fc3c 00000018 00744248 USER32!__fnDWORD+0x24
0012fc50 77d194d2 77d28f10 001596a0 001596a0 ntdll!KiUserCallbackDispatcher+0x13
界面根本就没办法显示,老是断在断点。这是因为windows
子系统会不断刷新界面,对文本框也是不断调用GetWindowTextW
所以,只能在CWnd::GetWindowTextW, CWnd::GetDlgItemTextW
打断点
操作如下图
然后点击下一步,得到如下堆栈:
看一下20007cd9附近的代码
非常疑惑,那些mfc100u_296, mfc100u_4805,mfc100u_7006
是哪些函数?可以用下面方法来确认:
其中20007CB3,20007CCB,20007CD3分别调用了mfc100u_296, mfc100u_4805,mfc100u_7006
。
那么20007cd9附近的代码如下:
由类CWnd
的成员函数原型
CWnd* GetDlgItem( int nID ) const;
void GetWindowText( CString& rString ) const;
可从
.text:20007CC0 lea ecx, [ebp+var_10]
.text:20007CC3 push ecx
知,ebp-10h存放着的内容应该是”hello”
.验证一下
也就是说,这里就是获取注册码的关键函数。说不定在这个函数会调用校验注册表的函数。
看一下20007cd9所在的函数20007C50
.text:20007C50 sub_20007C50 proc near ; DATA XREF: .rdata:20020CACo
.text:20007C50
.text:20007C50 var_18 = dword ptr -18h
.text:20007C50 var_14 = dword ptr -14h
.text:20007C50 var_10 = byte ptr -10h
.text:20007C50 var_C = dword ptr -0Ch
.text:20007C50 var_4 = dword ptr -4
.text:20007C50
.text:20007C50 push ebp
.text:20007C51 mov ebp, esp
.text:20007C53 push 0FFFFFFFFh
.text:20007C55 push offset loc_2001E1A1
.text:20007C5A mov eax, large fs:0
.text:20007C60 push eax
.text:20007C61 sub esp, 0Ch
.text:20007C64 push esi
.text:20007C65 push edi
.text:20007C66 mov eax, dword_20038018
.text:20007C6B xor eax, ebp
.text:20007C6D push eax
.text:20007C6E lea eax, [ebp+var_C]
.text:20007C71 mov large fs:0, eax
.text:20007C77 mov edi, ecx
.text:20007C79 mov eax, [edi+20h]
.text:20007C7C push eax ; hWnd
.text:20007C7D call ds:GetParent
.text:20007C83 push eax
.text:20007C84 call ds:mfc100u_4360 ; CWnd::FromHandle
.text:20007C8A push 0
.text:20007C8C push offset off_20038208
.text:20007C91 push offset off_2003805C
.text:20007C96 push 0
.text:20007C98 push eax
.text:20007C99 call __RTDynamicCast
.text:20007C9E lea esi, [eax+0CCh]
.text:20007CA4 add esp, 14h
.text:20007CA7 xor dl, dl
.text:20007CA9 mov ecx, esi
.text:20007CAB call sub_20004180
.text:20007CB0 lea ecx, [ebp+var_10]
.text:20007CB3 call ds:mfc100u_296 ; ATL::CStringT::CStringT
.text:20007CB9 mov [ebp+var_4], 0
.text:20007CC0 lea ecx, [ebp+var_10]
.text:20007CC3 push ecx
.text:20007CC4 push 7D3h
.text:20007CC9 mov ecx, edi
.text:20007CCB call ds:mfc100u_4805 ; CWnd::GetDlgItem
.text:20007CD1 mov ecx, eax
.text:20007CD3 call ds:mfc100u_7006 ; CWnd::GetWindowText
.text:20007CD9 push 0
.text:20007CDB lea edx, [ebp+var_10]
.text:20007CDE push edx
.text:20007CDF lea ecx, [ebp+var_14]
.text:20007CE2 call ds:[email protected]@[email protected]?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@[email protected]@@@@@[email protected]@[email protected]@@@Z ; VString::VString(ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>> const &,Str::SensitiveState)
.text:20007CE8 mov byte ptr [ebp+var_4], 1
.text:20007CEC mov eax, [eax]
.text:20007CEE mov ecx, esi
.text:20007CF0 call sub_200045D0
.text:20007CF5 mov [ebp+var_18], eax
.text:20007CF8 mov byte ptr [ebp+var_4], 0
.text:20007CFC mov esi, [ebp+var_14]
.text:20007CFF add esi, 0FFFFFFECh
.text:20007D02 lea eax, [esi+10h]
.text:20007D05 push eax ; lpAddend
.text:20007D06 call ds:InterlockedDecrement
.text:20007D0C test eax, eax
.text:20007D0E jg short loc_20007D31
.text:20007D10 cmp dword ptr [esi+0Ch], 1
.text:20007D14 jnz short loc_20007D27
.text:20007D16 mov ecx, [esi]
.text:20007D18 add ecx, 14h
.text:20007D1B mov eax, esi
.text:20007D1D jz short loc_20007D27
.text:20007D1F nop
.text:20007D20
.text:20007D20 loc_20007D20: ; CODE XREF: sub_20007C50+D5j
.text:20007D20 mov byte ptr [eax], 0
.text:20007D23 inc eax
.text:20007D24 dec ecx
.text:20007D25 jnz short loc_20007D20
.text:20007D27
.text:20007D27 loc_20007D27: ; CODE XREF: sub_20007C50+C4j
.text:20007D27 ; sub_20007C50+CDj
.text:20007D27 push esi ; Memory
.text:20007D28 call ds:free
.text:20007D2E add esp, 4
.text:20007D31
.text:20007D31 loc_20007D31: ; CODE XREF: sub_20007C50+BEj
.text:20007D31 mov esi, [ebp+var_18]
.text:20007D34 test esi, esi
.text:20007D36 jns short loc_20007D42 ; CMFCVisualManager::GetDockingPaneCaptionExtraHeight .text:20007D38 mov ecx, edi
.text:20007D3A call ds:__imp_mfc100u_10936
.text:20007D40 mov esi, eax
.text:20007D42
.text:20007D42 loc_20007D42: ; CODE XREF: sub_20007C50+E6j
.text:20007D42 mov [ebp+var_4], 0FFFFFFFFh
.text:20007D49 lea ecx, [ebp+var_10]
.text:20007D4C call ds:mfc100u_902 ; ATL::CStringT::~CStringT
.text:20007D52 mov eax, esi
.text:20007D54 mov ecx, [ebp+var_C]
.text:20007D57 mov large fs:0, ecx
.text:20007D5E pop ecx
.text:20007D5F pop edi
.text:20007D60 pop esi
.text:20007D61 mov esp, ebp
.text:20007D63 pop ebp
.text:20007D64 retn
.text:20007D64 sub_20007C50 endp
可以看到,除了20007CF0
调用了sub_200045D0
,其它地方调用的函数从名字来看,都不太可能是校验注册码。
现在看一下sub_200045D0
.text:200045D0 sub_200045D0 proc near ; CODE XREF: sub_20007C50+A0p
.text:200045D0 push edi
.text:200045D1 mov edi, ecx
.text:200045D3 call sub_20003EC0
.text:200045D8 test eax, eax
.text:200045DA jnz short loc_200045E6
.text:200045DC mov eax, [edi]
.text:200045DE mov edx, [eax+18h]
.text:200045E1 mov ecx, edi
.text:200045E3 pop edi
.text:200045E4 jmp edx
.text:200045E6 ; --------------------------------------------------------------------------- .text:200045E6
.text:200045E6 loc_200045E6: ; CODE XREF: sub_200045D0+Aj
.text:200045E6 cmp byte ptr [edi+29h], 0
.text:200045EA jz short loc_200045F6
.text:200045EC mov eax, [edi]
.text:200045EE mov edx, [eax+28h]
.text:200045F1 mov ecx, edi
.text:200045F3 pop edi
.text:200045F4 jmp edx
.text:200045F6 ; --------------------------------------------------------------------------- .text:200045F6
.text:200045F6 loc_200045F6: ; CODE XREF: sub_200045D0+1Aj
.text:200045F6 cmp eax, 1
.text:200045F9 jz short loc_20004605
.text:200045FB mov eax, [edi]
.text:200045FD mov edx, [eax+4]
.text:20004600 mov ecx, edi
.text:20004602 pop edi
.text:20004603 jmp edx
.text:20004605 ; --------------------------------------------------------------------------- .text:20004605
.text:20004605 loc_20004605: ; CODE XREF: sub_200045D0+29j
.text:20004605 or eax, 0FFFFFFFFh
.text:20004608 pop edi
.text:20004609 retn
.text:20004609 sub_200045D0 endp
这个函数有三处”jmp edx”
,非常奇怪。在200045DA
打断点,通过windbg
来确认那几处”jmp edx”
是跳转什么地方.
可以得到三个地址20006e20, 20006e70, 20006eb0
看一下这三处地方的代码
.text:20006E20 sub_20006E20 proc near ; DATA XREF: .rdata:20020458o
.text:20006E20 mov eax, 7EBh
.text:20006E25 retn
.text:20006E25 sub_20006E20 endp
.text:20006E70 sub_20006E70 proc near ; DATA XREF: .rdata:2002046Co
.text:20006E70 mov eax, 7DAh
.text:20006E75 retn
.text:20006E75 sub_20006E70 endp
.text:20006EB0 sub_20006EB0 proc near ; DATA XREF: .rdata:2002047Co
.text:20006EB0 mov eax, 7E9h
.text:20006EB5 retn
.text:20006EB5 sub_20006EB0 endp
再加上
.text:20004605 loc_20004605: ; CODE XREF: sub_200045D0+29j
.text:20004605 or eax, 0FFFFFFFFh
.text:20004608 pop edi
.text:20004609 retn
可知sub_200045D0
有四个返回值:7EB, 7DA, 7E9, -1。
看一下不同的返回值会对程序有什么影响。在20007CF5
(为调用sub_200045D0
的下一条指令)打断点.
当返回值为7EB时
当返回值为7DA时,
当返回值为7E9时,
当返回值为-1时,
可知,上面四个返回值中,7DA表明是注册码有效。那么研究一下sub_200045D0
在什么情况下返回7DA。
由上面的分析,7DA是从sub_200045D0
里下面分支
.text:200045DC mov eax, [edi]
.text:200045DE mov edx, [eax+18h]
得来的,而这个分支从这段代码来看
.text:200045D0 push edi
.text:200045D1 mov edi, ecx
.text:200045D3 call sub_20003EC0
.text:200045D8 test eax, eax
.text:200045DA jnz short loc_200045E6
.text:200045DC mov eax, [edi]
.text:200045DE mov edx, [eax+18h]
.text:200045E1 mov ecx, edi
.text:200045E3 pop edi
.text:200045E4 jmp edx
是当sub_20003EC0
的返回值为0时,sub_200045D0
才会返回7DA这个返回值。
由
.text:20007CDB lea edx, [ebp+var_10]
.text:20007CDE push edx
.text:20007CDF lea ecx, [ebp+var_14]
.text:20007CE2 call ds:[email protected]@[email protected]?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@[email protected]@@@@@[email protected]@[email protected]@@@Z ; VString::VString(ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>> const &,Str::SensitiveState)
.text:20007CE8 mov byte ptr [ebp+var_4], 1
.text:20007CEC mov eax, [eax]
.text:20007CEE mov ecx, esi
.text:20007CF0 call sub_200045D0
可知,当sub_20007C50
调用sub_200045D0
之前,把VString
构造函数的返回值(即this指针)所指向的内容通过eax传到sub_200045D0
,而VString
构造函数第一个参数则是ebp-10这个地址,按照上面分析是输入的注册码”hello”
看一下VString返回值的内容是怎样?
可知,VString
返回值指向地址存放着ASCII编码的注册码“hello”
。
根据返回值7DA可以得到license的字符串格式是
Name:[hello]
Company:[world]
Serial Number:[123456]
License Key:[7890abcdef]
Issue Date:[2020-12-31]
Features:[All]
但最后还是放弃了。虽然这个程序没加壳,也没做什么保护,个人对windows和MFC那一套不熟悉,且这个licenseHelper用了近500个函数来做检验。
花近2个月才筛选出13个关键函数。
暗号:53f4e