返回信息流这篇文章是我过年时候写的,纯属为了在看雪上篇个精--结果未遂:(
哈哈,不过我觉得还不是完全得一无是处,特贴出来大家研究研究。。
这是一条镜像帖。来源:北邮人论坛 / security / #21348同步于 2009/3/2
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Security机器人发帖
无聊--发过年时候写的一篇破解过程,希望增加下本版的技术含量
Dark
2009/3/2镜像同步46 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【文章标题】: MFC实战--Hex Workshop V4.2破解笔记(一)
【文章作者】: frank
【软件名称】: Hex Workshop
【下载地址】: 看雪站
【加壳方式】: 无
【保护方式】: 序列号
【编写语言】: MFC
【使用工具】: IDA,OLLYICE, EXESCOPE
【软件介绍】: 著名的16进制编辑工具
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
引言
如果你已经使用注册机注册过了的话,将附件中的注册表文件直接导入注册表即可将程序变成未注册。
具体实现下面正文会分析。废话不再表,直接进入正题。
1、查壳
========
首先、PEID打开文件--无壳:),MS VC7。
2、查找注册对话框
使用:Exescope, OllyIce
===========
Exescope打开hworks32.exe查找注册对话框--未果。
OllyIce载入Ctrl+N进入输入输出函数表,查找Dialog创建相关的函数并全部下断点。点击注册按钮,注册对话框正常弹出。
尝试用CreateWindow函数断依然正常弹出对话框。--到这里猜测注册相关实现应该不在hworks32.exe模块中。
Alt+E查看所有模块,软件载入的自己的模块共有bpsregwd.dll,hwapi.dll,bp_da.dll,diffeng.dll。
ExeScope逐个打开查看对话框资源,果然在第一个模块bpsregwd.dll中就发现了注册对话框。对话框ID--1002,Name对应Edit控件ID-1000,
Company对应Edit控件ID-1001,Key对应Edit控件ID-1002,OK按钮ID-1(使用默认的OK按钮)。
3、查找注册对话框类虚函数表
使用:IDA Pro
============
IDA Pro加载bpsregwd.dll, Ctrl+S 选择.rdata来到只读数据段--类虚函数表、MFC AFX_MSG_ENTRY均在该段。
虚函数表即一个函数指针数组,每个元素都指向一个虚函数。IDA已经帮我们分析出来了部分MFC库函数,没有分析出来的应该
是开发者重载过的。通过观察会发现只读段中包含不止一个虚函数表,那么哪个才是注册对话框类使用的呢?要解答这个问题就
需要知道虚函数表被初始化的时机。有虚函数的类在实例化时会调用构造函数完成以下三个工作:调用基类构造函数、初始化虚函数表指针、
初始化各数据成员。因此我们或许可以通过其他两个功能确定具体是哪个类的构造函数,进而确定对应的虚函数。
注册对话框基类CDialog基于资源的构造函数:CDialog::CDialog(uint,CWnd *)。 其中第一个参数即为指向对话框资源名字的指针或者其
ID值。具体如下例所示:
push eax
push 3EAh ==>1002,注册对话框ID
mov esi, ecx
call CDialog::CDialog(uint,CWnd *)
0x3EA是对话框资源ID,转换为10进制即为1002,因此可以确定该虚函数表地址即为注册对话框虚函数表。
4、 查找注册按钮事件处理函数
使用:IDA Pro
============
一般按钮(除ID为1、2外)事件处理函数在AFX_MSG_ENTRY中指定,查找各AFX_MSG_ENTRY的地址需要找到GetMessageMap函数。
本例中OK按钮为默认OK按钮(ID为1),其事件处理函数为注册对话框虚函数OnOK。
通过查看已经被IDA分析出的虚函数CDialog::DoModal(void)位置,结合MFC源代码可以发现OnOK函数被重载后即sub_10003DE0.
注意:虚函数表各虚函数相对位置在静态链接和共享MFC dll时是不同的,原因在于MFC源代码中用宏_AFXDLL控制。
本例中采用的就是静态链接,其虚函数个数比动态链接时要少。--可以自己用两种方式编译简单事例,对比发现区别。
下表是我整理出来的虚函数表:
rdata:1001C9F8 70 94 01 10 off_1001C9F8 dd offset sub_10019470
.rdata:1001C9F8 ; DATA XREF: sub_10003BD0+42o ==》引用
.rdata:1001C9F8 ; @@@注册对话框虚函数表@@@
.rdata:1001C9FC C0 3D 00 10 dd offset sub_10003DC0
.rdata:1001CA00 90 1B 00 10 dd offset nullsub_3
.rdata:1001CA04 D4 29 01 10 dd offset unknown_libname_25 ; MFC 3.1/4.0/4.2/8.0 32bit
.rdata:1001CA08 CD 31 01 10 dd offset CWnd::OnFinalRelease(void)
.rdata:1001CA0C 37 25 01 10 dd offset sub_10012537
.rdata:1001CA10 8B 25 01 10 dd offset sub_1001258B
.rdata:1001CA14 FA 3B 01 10 dd offset sub_10013BFA
.rdata:1001CA18 FA 3B 01 10 dd offset sub_10013BFA
.rdata:1001CA1C 3D 25 01 10 dd offset CCmdTarget::GetTypeLib(ulong,ITypeLib * *)
.rdata:1001CA20 B0 33 00 10 dd offset sub_100033B0 ==>GetMessageMap
.....
.rdata:1001CB38 34 2F 01 10 dd offset CDialog::DoModal(void) ==>已经被分析出的虚函数
.rdata:1001CB3C 70 37 00 10 dd offset sub_10003770
.rdata:1001CB40 9F 34 01 10 dd offset nullsub_5
.rdata:1001CB44 E0 3D 00 10 dd offset sub_10003DE0 ; OnOk注册按钮事件处理函数
.rdata:1001CB48 20 29 01 10 dd offset sub_10012920
.rdata:1001CB4C CC 31 01 10 dd offset nullsub_4
.rdata:1001CB50 6C CB 01 10 off_1001CB50 dd offset s_Cwinapp
【文章标题】: MFC实战--Hex Workshop V4.2破解笔记(二)
【文章作者】: frankbai
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
通过上文的分析已经找到了OK按钮事件的处理函数sub_10003DE0,以下是对该函数的解析:
...
push 1
mov ecx, esi ;==>注册对话框this指针
mov byte ptr [esp+108h+var_4], 1
call CWnd::UpdateData(int) ; ==>取得用户名,公司,Key信息
; sub_10003650
lea edi, [esi+80h] ; CString
; name ==》用户名
mov ecx, edi
call sub_10003B80
mov ecx, eax
call loc_10003A20
lea ebp, [esi+78h] ; CString
; company ==》公司名
mov ecx, ebp
call sub_10003B80
mov ecx, eax
call loc_10003A20
lea ebx, [esi+7Ch] ; CString
; key ==》用户输入的Key
mov ecx, ebx
call sub_10003B80
mov ecx, eax
call loc_10003A20
lea ecx, [esi+84h] ; CString==>暂时未知的字符串,后经分析可以得出,也可以动态跟踪得出为"Hex Workshop"
call sub_10003B80
mov ecx, eax
call loc_10003A20
mov eax, [edi] ; name
lea ecx, [esp+104h+name_buf]
sub ecx, eax
函数通过CWnd::UpdateData取得用户输入信息。让我们来看看这个函数:
BOOL CWnd::UpdateData(BOOL bSaveAndValidate)
{
ASSERT(::IsWindow(m_hWnd)); // calling UpdateData before DoModal?
CDataExchange dx(this, bSaveAndValidate);
// prevent control notifications from being dispatched during UpdateData
_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
HWND hWndOldLockout = pThreadState->m_hLockoutNotifyWindow;
ASSERT(hWndOldLockout != m_hWnd); // must not recurse
pThreadState->m_hLockoutNotifyWindow = m_hWnd;
BOOL bOK = FALSE; // assume failure
TRY
{
DoDataExchange(&dx); ==>关键函数,注册对话框类会重载该函数
bOK = TRUE; // it worked
}
CATCH(CUserException, e)
{
// validation failed - user already alerted, fall through
ASSERT(!bOK);
// Note: DELETE_EXCEPTION_(e) not required
}
AND_CATCH_ALL(e)
{
// validation failed due to OOM or other resource failure
e->ReportError(MB_ICONEXCLAMATION, AFX_IDP_INTERNAL_FAILURE);
ASSERT(!bOK);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
pThreadState->m_hLockoutNotifyWindow = hWndOldLockout;
return bOK;
}
要解释这个过程最好还是自己建一个基于对话框的应用程序,拖几个Edit控件在面板上,然后用类向导Ctrl+W针对该Edit控件
增加值型数据成员,最后查看对话框类的DoDataExchange函数的具体实现。我所建事例该函数如下:
void CSampDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSampDlg)
DDX_Text(pDX, IDC_EDIT1, m_edit1); ==>将控件与数据成员联系起来的函数
//}}AFX_DATA_MAP
}
DDX_Text函数通过控件ID更新与其相关的成员数据。因此我们只要找到被重载后的DoDataExchange既可以得到存放Name, Company,
Key值的具体数据成员。通过分析虚函数表可以发现,DoDataExchange被重载后为sub_10003650。以下是该函数实现:
sub_10003650 proc near
arg_0= dword ptr 0Ch
push esi
push edi
mov edi, [esp+arg_0]
mov esi, ecx ; this指针
lea eax, [esi+78h] ; Company Edit控件对应数据成员
push eax ; int
push 3E9h ; nIDDlgItem==>1001, Company Edit控件ID
push edi ; int
call sub_100182F4
lea ecx, [esi+7Ch] ; Key Edit控件对应数据成员
push ecx ; int
push 3EAh ; nIDDlgItem==>1002,Key Edit控件ID
push edi ; int
call sub_100182F4
add esi, 80h ; [esi+80h] Name Edit控件对应数据成员
push esi ; int
push 3E8h ; nIDDlgItem==>1000,Name Edit控件ID
push edi ; int
call sub_100182F4
pop edi
pop esi
retn 4
sub_10003650 endp
因此通过分析可以得到与我们输入的各字符串对应的数据成员:[esi+80h]-name; [esi+78h]-company; [esi+7Ch]/key。
下面继续分析按钮事件函数sub_10003DE0:
.text:10003E32 6A 01 push 1
.text:10003E34 8B CE mov ecx, esi
.text:10003E36 C6 84 24 04 01 00 00 01 mov byte ptr [esp+108h+var_4], 1
.text:10003E3E E8 4B 00 01 00 call CWnd::UpdateData(int) ; 取得用户名,公司,密码信息
.text:10003E3E ; sub_10003650
.text:10003E3E
.text:10003E43 8D BE 80 00 00 00 lea edi, [esi+80h] ; CString
.text:10003E43 ; name
.text:10003E49 8B CF mov ecx, edi
.text:10003E4B E8 30 FD FF FF call sub_10003B80
.text:10003E4B
.text:10003E50 8B C8 mov ecx, eax
.text:10003E52 E8 C9 FB FF FF call loc_10003A20
.text:10003E52
.text:10003E57 8D 6E 78 lea ebp, [esi+78h] ; CString
.text:10003E57 ; company
.text:10003E5A 8B CD mov ecx, ebp
.text:10003E5C E8 1F FD FF FF call sub_10003B80
.text:10003E5C
.text:10003E61 8B C8 mov ecx, eax
.text:10003E63 E8 B8 FB FF FF call loc_10003A20
.text:10003E63
.text:10003E68 8D 5E 7C lea ebx, [esi+7Ch] ; CString
.text:10003E68 ; key
.text:10003E6B 8B CB mov ecx, ebx
.text:10003E6D E8 0E FD FF FF call sub_10003B80
.text:10003E6D
.text:10003E72 8B C8 mov ecx, eax
.text:10003E74 E8 A7 FB FF FF call loc_10003A20
.text:10003E74
.text:10003E79 8D 8E 84 00 00 00 lea ecx, [esi+84h] ; CString
.text:10003E7F E8 FC FC FF FF call sub_10003B80
.text:10003E7F
.text:10003E84 8B C8 mov ecx, eax
.text:10003E86 E8 95 FB FF FF call loc_10003A20
.text:10003E86
.text:10003E8B 8B 07 mov eax, [edi] ; name
.text:10003E8D 8D 8C 24 A8 00 00 00 lea ecx, [esp+104h+name_buf]
.text:10003E94 2B C8 sub ecx, eax
.text:10003E94
.text:10003E96
.text:10003E96 loc_10003E96: ; CODE XREF: sub_10003DE0+BEj
.text:10003E96 8A 10 mov dl, [eax] ; strcpy(namebuf, name)
.text:10003E98 88 14 01 mov [ecx+eax], dl
.text:10003E9B 40 inc eax
.text:10003E9C 84 D2 test dl, dl
.text:10003E9E 75 F6 jnz short loc_10003E96
.text:10003E9E
.text:10003EA0 8B 45 00 mov eax, [ebp+0] ; company
.text:10003EA3 8D 54 24 58 lea edx, [esp+104h+company_buf]
.text:10003EA7 2B D0 sub edx, eax
.text:10003EA9 8D A4 24 00 00 00 00 lea esp, [esp+0]
.text:10003EA9
.text:10003EB0
.text:10003EB0 loc_10003EB0: ; CODE XREF: sub_10003DE0+D8j
.text:10003EB0 8A 08 mov cl, [eax] ; strcpy(company_buf, company)
.text:10003EB2 88 0C 02 mov [edx+eax], cl
.text:10003EB5 40 inc eax
.text:10003EB6 84 C9 test cl, cl
.text:10003EB8 75 F6 jnz short loc_10003EB0
.text:10003EB8
.text:10003EBA 8B 03 mov eax, [ebx] ; key
.text:10003EBC 8D 54 24 18 lea edx, [esp+104h+key_buf]
.text:10003EC0 2B D0 sub edx, eax
.text:10003EC0
.text:10003EC2
.text:10003EC2 loc_10003EC2: ; CODE XREF: sub_10003DE0+EAj
.text:10003EC2 8A 08 mov cl, [eax] ; strcpy(key_buf, key)
.text:10003EC4 88 0C 02 mov [edx+eax], cl
.text:10003EC7 40 inc eax
.text:10003EC8 84 C9 test cl, cl
.text:10003ECA 75 F6 jnz short loc_10003EC2
.text:10003ECA
.text:10003ECC 8B 86 84 00 00 00 mov eax, [esi+84h]
.text:10003ED2 8D 54 24 38 lea edx, [esp+104h+var_CC]
.text:10003ED6 2B D0 sub edx, eax
.text:10003ED6
.text:10003ED8
.text:10003ED8 loc_10003ED8: ; CODE XREF: sub_10003DE0+100j
.text:10003ED8 8A 08 mov cl, [eax] ; strcpy(unk_buf, unk_string)
.text:10003EDA 88 0C 02 mov [edx+eax], cl
.text:10003EDD 40 inc eax
.text:10003EDE 84 C9 test cl, cl
.text:10003EE0 75 F6 jnz short loc_10003ED8
.text:10003EE0
.text:10003EE2 E8 20 55 01 00 call AfxGetModuleState(void)
.text:10003EE2
.text:10003EE7 8B 40 04 mov eax, [eax+4]
.text:10003EEA 8B 10 mov edx, [eax]
.text:10003EEC 6A 01 push 1
.text:10003EEE 8B C8 mov ecx, eax
.text:10003EF0 FF 92 9C 00 00 00 call dword ptr [edx+9Ch]
.text:10003EF6 8B 3D 54 C2 01 10 mov edi, ds:Sleep
.text:10003EFC 68 D0 07 00 00 push 7D0h ; dwMilliseconds
.text:10003F01 FF D7 call edi ; Sleep
.text:10003F03 E8 FF 54 01 00 call AfxGetModuleState(void)
.text:10003F03
.text:10003F08 8B 40 04 mov eax, [eax+4]
.text:10003F0B 8B 10 mov edx, [eax]
.text:10003F0D 6A FF push 0FFFFFFFFh
.text:10003F0F 8B C8 mov ecx, eax
.text:10003F11 FF 92 9C 00 00 00 call dword ptr [edx+9Ch] ; DoWaitCursor
.text:10003F11 ; 0 => restore, 1=> begin, -1=> end
.text:10003F17 8D 44 24 18 lea eax, [esp+10Ch+var_F4] ; [esp+104h+key_buf]
.text:10003F1B 50 push eax ; key
.text:10003F1C 8B 86 88 02 00 00 mov eax, [esi+288h]
.text:10003F22 8D 4C 24 5C lea ecx, [esp+110h+var_B4] ; [esp+104h+company_buf]
.text:10003F26 51 push ecx ; company
.text:10003F27 8B 4E 70 mov ecx, [esi+70h]
.text:10003F2A 8D 94 24 B0 00 00 00 lea edx, [esp+114h+var_64] ; [esp+104h+name_buf]
.text:10003F31 52 push edx ; name
.text:10003F32 33 D2 xor edx, edx
.text:10003F34 8A 56 74 mov dl, [esi+74h]
.text:10003F37 50 push eax
.text:10003F38 51 push ecx
.text:10003F39 8D 44 24 4C lea eax, [esp+120h+var_D4] ; [esp+104h+unk_buf]
.text:10003F3D 52 push edx
.text:10003F3E 50 push eax ; pProgramFile
.text:10003F3F E8 5C EC FF FF call key_verify ; 参数:1/pProgramFile
.text:10003F3F ; 2/m_data74: 04,
.text:10003F3F ; 3/m_data70: 07,
.text:10003F3F ; 4/m_data288: 0x40800000
.text:10003F3F ; 5/pName, 6/pCom, 7/pKey
.text:10003F3F ;
.text:10003F3F ; 返回值: 0/成功, 非0/失败
.text:10003F3F
.text:10003F44 83 C4 1C add esp, 1Ch
.text:10003F47 85 C0 test eax, eax
.text:10003F49 75 4A jnz short loc_10003F95
.text:10003F49
.text:10003F4B 6A 0D push 0Dh ; Thank you! Your product has been unlocked.
.text:10003F4B ;
.text:10003F4D E8 92 28 01 00 call AfxFindStringResourceHandle(uint)
.text:10003F4D
.text:10003F52 85 C0 test eax, eax
.text:10003F54 74 0C jz short loc_10003F62
.text:10003F54
.text:10003F56 6A 0D push 0Dh
.text:10003F58 50 push eax
.text:10003F59 8D 4C 24 1C lea ecx, [esp+114h+var_F8]
.text:10003F5D E8 4E F9 FF FF call loc_100038B0
.text:10003F5D
.text:10003F62
.text:10003F62 loc_10003F62: ; CODE XREF: sub_10003DE0+174j
.text:10003F62 6A 0B push 0Bh ; Success
.text:10003F64 E8 7B 28 01 00 call AfxFindStringResourceHandle(uint)
.text:10003F64
.text:10003F69 85 C0 test eax, eax
.text:10003F6B 74 0C jz short loc_10003F79
.text:10003F6B
.text:10003F6D 6A 0B push 0Bh
.text:10003F6F 50 push eax
.text:10003F70 8D 4C 24 18 lea ecx, [esp+11Ch+var_104]
.text:10003F74 E8 37 F9 FF FF call loc_100038B0
.text:10003F74
.text:10003F79
.text:10003F79 loc_10003F79: ; CODE XREF: sub_10003DE0+18Bj
.text:10003F79 8B 4C 24 10 mov ecx, [esp+11Ch+var_10C]
.text:10003F7D 8B 54 24 14 mov edx, [esp+11Ch+lpText]
.text:10003F81 6A 40 push 40h ; uType
.text:10003F83 51 push ecx ; int
.text:10003F84 52 push edx ; lpText
.text:10003F85 8B CE mov ecx, esi
.text:10003F87 E8 A4 FE 00 00 call sub_10013E30
.text:10003F87
.text:10003F8C 8B CE mov ecx, esi
.text:10003F8E E8 74 E9 00 00 call CDialog::OnOK(void)
.text:10003F8E
.text:10003F93 EB 70 jmp short loc_10004005
.text:10003F93
.text:10003F95 ; ---------------------------------------------------------------------------
.text:10003F95
.text:10003F95 loc_10003F95: ; CODE XREF: sub_10003DE0+169j
.text:10003F95 6A 0E push 0Eh
.text:10003F97 E8 48 28 01 00 call AfxFindStringResourceHandle(uint)
.text:10003F97
.text:10003F9C 85 C0 test eax, eax
.text:10003F9E 74 0C jz short loc_10003FAC
.text:10003F9E
.text:10003FA0 6A 0E push 0Eh ; Please check your key and try again.
.text:10003FA0 ; If this problem persists, please contact service@bpsoft.com.
.text:10003FA0 ;
.text:10003FA2 50 push eax
.text:10003FA3 8D 4C 24 1C lea ecx, [esp+114h+var_F8]
.text:10003FA7 E8 04 F9 FF FF call loc_100038B0
.text:10003FA7
.text:10003FAC
.text:10003FAC loc_10003FAC: ; CODE XREF: sub_10003DE0+1BEj
.text:10003FAC 6A 0C push 0Ch ; Invalid Key
.text:10003FAC ;
.text:10003FAE E8 31 28 01 00 call AfxFindStringResourceHandle(uint)
.text:10003FAE
.text:10003FB3 85 C0 test eax, eax
.text:10003FB5 74 0C jz short loc_10003FC3
.text:10003FB5
.text:10003FB7 6A 0C push 0Ch
.text:10003FB9 50 push eax
.text:10003FBA 8D 4C 24 18 lea ecx, [esp+11Ch+var_104]
.text:10003FBE E8 ED F8 FF FF call loc_100038B0
.text:10003FBE
.text:10003FC3
.text:10003FC3 loc_10003FC3: ; CODE XREF: sub_10003DE0+1D5j
.text:10003FC3 8B 44 24 10 mov eax, [esp+11Ch+var_10C]
.text:10003FC7 8B 4C 24 14 mov ecx, [esp+11Ch+lpText]
.text:10003FCB 6A 40 push 40h ; uType
.text:10003FCD 50 push eax ; int
.text:10003FCE 51 push ecx ; lpText
.text:10003FCF 8B CE mov ecx, esi
.text:10003FD1 E8 5A FE 00 00 call sub_10013E30
.text:10003FD1
.text:10003FD6 E8 2C 54 01 00 call AfxGetModuleState(void)
.text:10003FD6
.text:10003FDB 8B 40 04 mov eax, [eax+4]
.text:10003FDE 8B 10 mov edx, [eax]
.text:10003FE0 6A 01 push 1
.text:10003FE2 8B C8 mov ecx, eax
.text:10003FE4 FF 92 9C 00 00 00 call dword ptr [edx+9Ch]
.text:10003FEA 68 D0 07 00 00 push 7D0h ; dwMilliseconds
.text:10003FEF FF D7 call edi ; Sleep
.text:10003FF1 E8 11 54 01 00 call AfxGetModuleState(void)
.text:10003FF1
.text:10003FF6 8B 40 04 mov eax, [eax+4]
.text:10003FF9 8B 10 mov edx, [eax]
.text:10003FFB 6A FF push 0FFFFFFFFh
.text:10003FFD 8B C8 mov ecx, eax
.text:10003FFF FF 92 9C 00 00 00 call dword ptr [edx+9Ch]
基本分析我都已经在注释中写明,其中name_buf, company_buf, ke_buf, key_verify是我根据分析重新命名的结果,读者可参照地址自行命名。
这里要说明的是:弹出出错以及正确对话框均在函数sub_10013E30中完成。该函数共三个参数:lpText, lpCaption, type。其中
lpText, lpCaption由loc_100038B0函数通过调用LoadResource载入字符串资源。
具体载入哪两个字串资源也即弹出哪个对话框(正确或错误)由key_verify的返回值决定,即10003F3F处调用的函数。由此我们找到了
真正关键的函数,这也是我把其命名为key_verify的原因所在。观察得到该函数共有7个参数,返回值分为0和非0--0/成功,软件成功注册;
非0/失败,弹出出错对话框。
该函数声明如注释中所述:
.text:10003F3E 50 push eax ; pProgramFile
.text:10003F3F E8 5C EC FF FF call key_verify ; 参数:1/pProgramFile
.text:10003F3F ; 2/m_data74: 04,
.text:10003F3F ; 3/m_data70: 07,
.text:10003F3F ; 4/m_data288: 0x40800000
.text:10003F3F ; 5/pName, 6/pCom, 7/pKey
.text:10003F3F ;
.text:10003F3F ; 返回值: 0/成功, 非0/失败
其中各参数可以通过动态调试得到,也可以静态分析得到。在这里我用的是静态分析,动态调试只是作为验证想法的辅助手段。
静态分析得到的信息是:参数1-未知字符串指针,参数2~4-注册对话框实例数据成员,参数5-Name字符串指针,参数6-Company字符串指针,
参数7-Key字符串指针。
注册表文件
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\BreakPoint License Manager]
"Hex Workshop (2722-BE)"=hex:b9,ef,4d,d9,9f,0a,6c,6c,f7,d5,3b,34,67,0f,fd,e0,\
cb,1e,fa,c1,92,3d,f4,83,23,7b,e8,07,41,f6,d0,0f,df,82,d3,7a,7a,b0,30,4b,55,\
c0,e2,1a,6b,64,0f,fd,db,c8,1e,fa,ba,91,3d,f4,7b,23,7b,e8,f8,46,f6,d0,e1,8d,\
ec,a1,d2,1b,d9,43,b6,37,b2,87,7e,6f,64,0f,e8,de,c8,1e,c5,bd,91,3d,9c,7b,23,\
7b,2f,f7,46,f6,47,ee,8d,ec,96,dc,1b,d9,37,b9,37,b2,74,72,6f,64,a1,8a,ac,ad,\
93,a0,ce,e5,92,e1,1e,47,f1,27,f7,46,c2,4f,ee,8d,a4,9f,dc,1b,6a,3f,b9,37,f7,\
7e,72,6f,ca,fd,e4,de,b0,fb,c9,bd,47,f7,93,7b,a9,ee,27,f7,7b,dd,4f,ee,de,ba,\
9f,dc,97,75,3f,b9,04,eb,7e,72,24,d6,fd,e4,64,ac,fb,c9,e7,58,f7,93,e0,b1,ee,\
27,b4,26,90,00,d1,c7,ba,9f,91,8f,75,3f,11,1f,eb,7e,16,3e,d6,fd,18,7c,ac,fb,\
07,f8,58,f7,38,f0,b1,ee,01,85,1b,fd,fd,af,b5,d1,1c,e9,e0,05,e5,02,1f,eb,f7,\
05,3e,d6,d2,0b,7c,ac,9b,17,f8,58,09,2f,f0,b1,53,5e,e0,63,e6,bc,c0,c7,8d,79,\
81,8f,58,f3,02,1f,f4,e6,05,3e,8f,cd,0b,7c,72,fb,6b,b1,0b,56,53,b9,5b,e8,f4,\
a9,23,d9,bc,c0,0f,b2,f9,c1,54,64,f3,02,e4,c8,e6,05,85,91,cd,0b,44,23,9b,17,\
c7,46,36,2f,de,8d,6c,5e,ed,1b,d9,bc,89,37,b2,79,41,6f,64,f3,d7,de,c8,e6,fa,\
bd,91,cd,a3,7b,23,9b,10,f7,46,36,78,ee,8d,6c,a9,dc,1b,d9,09,b9,37,b2,48,72,\
6f,64,cc,e4,de,c8,c4,c9,bd,91,d7,93,7b,23,f1,27,f7,46,82,4f,ee,8d,64,9f,dc,\
1b,aa,3e,b9,37,37,7d,72,6f,0a,fa,e4,de,70,f4,c9,bd,87,e8,93,7b,69,d1,27,f7,\
bb,a2,4f,ee,1e,45,9f,dc,6a,b5,0b,56
[HKEY_LOCAL_MACHINE\SOFTWARE\BreakPoint\Licenses]
"Hex Workshop (2722-BE)"=hex:b9,ef,4d,d9,9f,0a,6c,6c,f7,d5,3b,34,67,0f,fd,e0,\
cb,1e,fa,c1,92,3d,f4,83,23,7b,e8,07,41,f6,d0,0f,df,82,d3,7a,7a,b0,30,4b,55,\
c0,e2,1a,6b,64,0f,fd,db,c8,1e,fa,ba,91,3d,f4,7b,23,7b,e8,f8,46,f6,d0,e1,8d,\
ec,a1,d2,1b,d9,43,b6,37,b2,87,7e,6f,64,0f,e8,de,c8,1e,c5,bd,91,3d,9c,7b,23,\
7b,2f,f7,46,f6,47,ee,8d,ec,96,dc,1b,d9,37,b9,37,b2,74,72,6f,64,a1,8a,ac,ad,\
93,a0,ce,e5,92,e1,1e,47,f1,27,f7,46,c2,4f,ee,8d,a4,9f,dc,1b,6a,3f,b9,37,f7,\
7e,72,6f,ca,fd,e4,de,b0,fb,c9,bd,47,f7,93,7b,a9,ee,27,f7,7b,dd,4f,ee,de,ba,\
9f,dc,97,75,3f,b9,04,eb,7e,72,24,d6,fd,e4,64,ac,fb,c9,e7,58,f7,93,e0,b1,ee,\
27,b4,26,90,00,d1,c7,ba,9f,91,8f,75,3f,11,1f,eb,7e,16,3e,d6,fd,18,7c,ac,fb,\
07,f8,58,f7,38,f0,b1,ee,01,85,1b,fd,fd,af,b5,d1,1c,e9,e0,05,e5,02,1f,eb,f7,\
05,3e,d6,d2,0b,7c,ac,9b,17,f8,58,09,2f,f0,b1,53,5e,e0,63,e6,bc,c0,c7,8d,79,\
81,8f,58,f3,02,1f,f4,e6,05,3e,8f,cd,0b,7c,72,fb,6b,b1,0b,56,53,b9,5b,e8,f4,\
a9,23,d9,bc,c0,0f,b2,f9,c1,54,64,f3,02,e4,c8,e6,05,85,91,cd,0b,44,23,9b,17,\
c7,46,36,2f,de,8d,6c,5e,ed,1b,d9,bc,89,37,b2,79,41,6f,64,f3,d7,de,c8,e6,fa,\
bd,91,cd,a3,7b,23,9b,10,f7,46,36,78,ee,8d,6c,a9,dc,1b,d9,09,b9,37,b2,48,72,\
6f,64,cc,e4,de,c8,c4,c9,bd,91,d7,93,7b,23,f1,27,f7,46,82,4f,ee,8d,64,9f,dc,\
1b,aa,3e,b9,37,37,7d,72,6f,0a,fa,e4,de,70,f4,c9,bd,87,e8,93,7b,69,d1,27,f7,\
bb,a2,4f,ee,1e,45,9f,dc,6a,b5,0b,56
【 在 Dark 的大作中提到: 】
: 这篇文章是我过年时候写的,纯属为了在看雪上篇个精--结果未遂:(
: 哈哈,不过我觉得还不是完全得一无是处,特贴出来大家研究研究。。
【文章标题】: MFC实战--Hex Workshop V4.2破解笔记(三)
【文章作者】: frank
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
下面来解析函数:key_verify
.text:10002BA0 key_verify proc near ; CODE XREF: _102+2Ep
.text:10002BA0 ; sub_10003DE0+15Fp
.text:10002BA0
.text:10002BA0 var_1D8= dword ptr -1D8h
.text:10002BA0 var_1C8= byte ptr -1C8h
.text:10002BA0 var_1C7= dword ptr -1C7h
.text:10002BA0 var_1C0= dword ptr -1C0h
.text:10002BA0 var_1BC= dword ptr -1BCh
.text:10002BA0 var_1B8= dword ptr -1B8h
.text:10002BA0 var_1B4= dword ptr -1B4h
.text:10002BA0 var_1B0= dword ptr -1B0h
.text:10002BA0 var_190= dword ptr -190h
.text:10002BA0 var_140= dword ptr -140h
.text:10002BA0 var_F0= byte ptr -0F0h
.text:10002BA0 var_D0= dword ptr -0D0h
.text:10002BA0 var_B0= dword ptr -0B0h
.text:10002BA0 var_AC= dword ptr -0ACh
.text:10002BA0 var_A8= dword ptr -0A8h
.text:10002BA0 var_A4= dword ptr -0A4h
.text:10002BA0 var_A0= dword ptr -0A0h
.text:10002BA0 var_9C= dword ptr -9Ch
.text:10002BA0 var_98= dword ptr -98h
.text:10002BA0 var_94= dword ptr -94h
.text:10002BA0 var_90= dword ptr -90h
.text:10002BA0 var_8C= dword ptr -8Ch
.text:10002BA0 var_88= dword ptr -88h
.text:10002BA0 pProgramFile= dword ptr 8
.text:10002BA0 arg_4= dword ptr 0Ch
.text:10002BA0 arg_8= dword ptr 10h
.text:10002BA0 arg_C= dword ptr 14h
.text:10002BA0 pName= dword ptr 18h
.text:10002BA0 pCompany= dword ptr 1Ch
.text:10002BA0 pKey= dword ptr 20h
.text:10002BA0
.text:10002BA0 55 push ebp
.text:10002BA1 8B EC mov ebp, esp
.text:10002BA3 83 E4 F8 and esp, 0FFFFFFF8h
.text:10002BA6 81 EC CC 01 00 00 sub esp, 1CCh
.text:10002BAC 53 push ebx
.text:10002BAD 56 push esi
.text:10002BAE 57 push edi
.text:10002BAF 6A 00 push 0
.text:10002BB1 E8 6C 35 00 00 call __time64 =》生成随机变量
.text:10002BB1
.text:10002BB6 8B 5D 20 mov ebx, [ebp+pKey]
.text:10002BB9 83 C4 04 add esp, 4
.text:10002BBC 8B FB mov edi, ebx
.text:10002BBE 8B F0 mov esi, eax
.text:10002BC0 89 54 24 24 mov [esp+1D8h+var_1B4], edx
.text:10002BC4 E8 E7 F9 FF FF call sub_100025B0
.text:10002BC4
.text:10002BC9 84 C0 test al, al
.text:10002BCB 0F 85 0E 02 00 00 jnz loc_10002DDF
.text:10002BCB
.text:10002BD1 8D 44 24 12 lea eax, [esp+1D8h+var_1C7+1]
.text:10002BD5 50 push eax ; int
.text:10002BD6 8D 4C 24 14 lea ecx, [esp+14h] ; [esp+1DCh+var_1C8]
.text:10002BDA 51 push ecx ; int
.text:10002BDB 8D 54 24 1B lea edx, [esp+1E0h+var_1C7+2]
.text:10002BDF 52 push edx ; int
.text:10002BE0 8D 44 24 20 lea eax, [esp+1E4h+var_1C7+3] ; [esp+1E4h+var_1C4]
.text:10002BE4 50 push eax ; int
.text:10002BE5 8D 4C 24 21 lea ecx, [esp+1E8h+var_1C7]
.text:10002BE9 51 push ecx ; int
.text:10002BEA 8D 54 24 2C lea edx, [esp+1ECh+var_1C0]
.text:10002BEE 52 push edx ; int
.text:10002BEF 8D 44 24 34 lea eax, [esp+1F0h+var_1BC]
.text:10002BF3 50 push eax ; int
.text:10002BF4 53 push ebx ; char *
.text:10002BF5 E8 36 F7 FF FF call sub_10002330 ; Byte func(pKey, pInt, pInt, pByte,
.text:10002BF5 ; pInt, pByte, pByte, pByte);
.text:10002BF5 ;
.text:10002BF5 ; 参数:1/pKey
.text:10002BF5 ;
.text:10002BF5 ; 返回值:0/失败,非0/成功
.text:10002BF5
.text:10002BFA 83 C4 20 add esp, 20h
.text:10002BFD 84 C0 test al, al
.text:10002BFF 0F 84 F2 01 00 00 jz loc_10002DF7
.text:10002BFF
.text:10002C05 8B 4D 0C mov ecx, [ebp+arg_4] ; 04
.text:10002C08 38 4C 24 11 cmp byte ptr [esp+1D8h+var_1C7], cl
.text:10002C0C 0F 85 C1 01 00 00 jnz loc_10002DD3
.text:10002C0C
.text:10002C12 8B 44 24 14 mov eax, [esp+1D8h+var_1C7+3] ; [esp+1D8h+var_1C4]
.text:10002C12 ; 0b***00111
.text:10002C16 8B 7D 10 mov edi, [ebp+arg_8]
.text:10002C19 3B C7 cmp eax, edi
.text:10002C1B 0F 8C B2 01 00 00 jl loc_10002DD3
.text:10002C1B
.text:10002C21 8D 54 24 28 lea edx, [esp+1D8h+var_1B0]
.text:10002C25 52 push edx
.text:10002C26 50 push eax ; 2722
.text:10002C27 8B 45 08 mov eax, [ebp+pProgramFile] ; Hex WorkShop
.text:10002C2A 51 push ecx ; 04->BE
.text:10002C2B 50 push eax
.text:10002C2C E8 0F F1 FF FF call sub_10001D40 ; 注册表键值变形
.text:10002C2C ; 并将结果存入
.text:10002C2C ; 参数4所指地址
.text:10002C2C
.text:10002C31 83 C4 10 add esp, 10h
.text:10002C34 84 C0 test al, al
.text:10002C36 75 10 jnz short loc_10002C48
.text:10002C36
.text:10002C38 B9 6B 00 00 00 mov ecx, 6Bh
.text:10002C3D 33 C0 xor eax, eax
.text:10002C3F 8D 7C 24 28 lea edi, [esp+1D8h+var_1B0]
.text:10002C43 F3 AB rep stosd ; 函数返回值为0时
.text:10002C43 ; 使用_time64函数
.text:10002C43 ; 返回值低32bit填充缓冲区
.text:10002C45 8B 7D 10 mov edi, [ebp+arg_8]
.text:10002C45
.text:10002C48
.text:10002C48 loc_10002C48: ; CODE XREF: key_verify+96j
.text:10002C48 8D 54 24 28 lea edx, [esp+1D8h+var_1B0]
.text:10002C4C 8B C3 mov eax, ebx ; pKey
.text:10002C4E 2B D3 sub edx, ebx
.text:10002C4E
.text:10002C50
.text:10002C50 loc_10002C50: ; CODE XREF: key_verify+B8j
.text:10002C50 8A 08 mov cl, [eax]
.text:10002C52 88 0C 02 mov [edx+eax], cl
.text:10002C55 40 inc eax
.text:10002C56 84 C9 test cl, cl
.text:10002C58 75 F6 jnz short loc_10002C50
.text:10002C58
.text:10002C5A 8B 45 18 mov eax, [ebp+pName] ; pName
.text:10002C5D 8D 54 24 48 lea edx, [esp+1D8h+var_190]
.text:10002C61 2B D0 sub edx, eax
.text:10002C61
.text:10002C63
.text:10002C63 loc_10002C63: ; CODE XREF: key_verify+CBj
.text:10002C63 8A 08 mov cl, [eax]
.text:10002C65 88 0C 02 mov [edx+eax], cl
.text:10002C68 40 inc eax
.text:10002C69 84 C9 test cl, cl
.text:10002C6B 75 F6 jnz short loc_10002C63
.text:10002C6B
.text:10002C6D 8B 45 1C mov eax, [ebp+pCompany] ; pComapany
.text:10002C70 8D 94 24 98 00 00 00 lea edx, [esp+1D8h+var_140]
.text:10002C77 2B D0 sub edx, eax
.text:10002C79 8D A4 24 00 00 00 00 lea esp, [esp+0]
.text:10002C79
.text:10002C80
.text:10002C80 loc_10002C80: ; CODE XREF: key_verify+E8j
.text:10002C80 8A 08 mov cl, [eax]
.text:10002C82 88 0C 02 mov [edx+eax], cl
.text:10002C85 40 inc eax
.text:10002C86 84 C9 test cl, cl
.text:10002C88 75 F6 jnz short loc_10002C80
.text:10002C88
.text:10002C8A 8B 4C 24 1C mov ecx, [esp+1D8h+var_1BC]
.text:10002C8E 51 push ecx ; ****04$$-******-****
.text:10002C8E ; $$:0b***00111
.text:10002C8E ; field1-field2-field3
.text:10002C8E ; =>field2
.text:10002C8F 8D 94 24 EC 00 00 00 lea edx, [esp+1DCh+var_F0]
.text:10002C96 68 B4 C9 01 10 push offset s_06d ; "%06d"
.text:10002C9B 52 push edx ; char *
.text:10002C9C E8 B3 28 00 00 call _sprintf
.text:10002C9C
.text:10002CA1 8B 5D 08 mov ebx, [ebp+pProgramFile]
.text:10002CA4 8D 94 24 14 01 00 00 lea edx, [esp+1E4h+var_D0]
.text:10002CAB 83 C4 0C add esp, 0Ch
.text:10002CAE 8B C3 mov eax, ebx
.text:10002CB0 2B D3 sub edx, ebx
.text:10002CB0
.text:10002CB2
.text:10002CB2 loc_10002CB2: ; CODE XREF: key_verify+11Aj
.text:10002CB2 8A 08 mov cl, [eax] ; strcpy(var_D0, pProgramFile)
.text:10002CB4 88 0C 02 mov [edx+eax], cl
.text:10002CB7 40 inc eax
.text:10002CB8 84 C9 test cl, cl
.text:10002CBA 75 F6 jnz short loc_10002CB2
.text:10002CBA
.text:10002CBC 8B 44 24 18 mov eax, [esp+1D8h+var_1C0] ; ****04$$-******-****
.text:10002CBC ; $$:0b***00111
.text:10002CBC ; field1-field2-field3
.text:10002CBC ; =>*pArg3
.text:10002CC0 8B 4D 14 mov ecx, [ebp+arg_C] ; [esi+288h]
.text:10002CC3 89 84 24 28 01 00 00 mov [esp+1D8h+var_B0], eax
.text:10002CCA 8A 44 24 10 mov al, [esp+1D8h+var_1C8] ; *pArg7
.text:10002CCE 84 C0 test al, al
.text:10002CD0 89 8C 24 50 01 00 00 mov [esp+1D8h+var_88], ecx
.text:10002CD7 74 7C jz short loc_10002D55
.text:10002CD7
.text:10002CD9 8B 8C 24 38 01 00 00 mov ecx, [esp+1D8h+var_A0]
.text:10002CE0 85 C9 test ecx, ecx
.text:10002CE2 B8 01 00 00 00 mov eax, 1
.text:10002CE7 89 84 24 2C 01 00 00 mov [esp+1D8h+var_AC], eax
.text:10002CEE 0F 85 B7 00 00 00 jnz loc_10002DAB
.text:10002CEE
.text:10002CF4 6A 00 push 0
.text:10002CF6 6A 00 push 0
.text:10002CF8 6A 00 push 0
.text:10002CFA 6A 0F push 0Fh
.text:10002CFC 8D 4C 24 30 lea ecx, [esp+1E8h+var_1B8]
.text:10002D00 C7 84 24 40 01 00 00 00+mov [esp+1E8h+var_A8], 0
.text:10002D0B 89 84 24 44 01 00 00 mov [esp+1E8h+var_A4], eax
.text:10002D12 89 84 24 48 01 00 00 mov [esp+1E8h+var_A0], eax
.text:10002D19 C7 84 24 4C 01 00 00 0F+mov [esp+1E8h+var_9C], 0Fh
.text:10002D24 89 B4 24 50 01 00 00 mov [esp+1E8h+var_98], esi
.text:10002D2B 89 B4 24 54 01 00 00 mov [esp+1E8h+var_94], esi
.text:10002D32 E8 69 FB FF FF call sub_100028A0
.text:10002D32
.text:10002D37 8B 08 mov ecx, [eax]
.text:10002D39 8B 50 04 mov edx, [eax+4]
.text:10002D3C 8B 45 0C mov eax, [ebp+arg_4]
.text:10002D3F 03 CE add ecx, esi
.text:10002D41 57 push edi
.text:10002D42 50 push eax
.text:10002D43 89 54 24 2C mov [esp+1E0h+var_1B4], edx
.text:10002D47 89 8C 24 50 01 00 00 mov [esp+1E0h+var_90], ecx
.text:10002D4E E8 8D EE FF FF call sub_10001BE0
.text:10002D4E
.text:10002D53 EB 53 jmp short loc_10002DA8
.text:10002D53
.text:10002D55 ; ---------------------------------------------------------------------------
.text:10002D55
.text:10002D55 loc_10002D55: ; CODE XREF: key_verify+137j
.text:10002D55 8B 4D 0C mov ecx, [ebp+arg_4]
.text:10002D58 33 C0 xor eax, eax
.text:10002D5A 57 push edi
.text:10002D5B 51 push ecx
.text:10002D5C 89 84 24 34 01 00 00 mov [esp+1E0h+var_AC], eax
.text:10002D63 89 84 24 38 01 00 00 mov [esp+1E0h+var_A8], eax
.text:10002D6A 89 84 24 3C 01 00 00 mov [esp+1E0h+var_A4], eax
.text:10002D71 C7 84 24 40 01 00 00 01+mov [esp+1E0h+var_A0], 1
.text:10002D7C C7 84 24 44 01 00 00 FF+mov [esp+1E0h+var_9C], 0FFFFFFFFh
.text:10002D87 89 B4 24 48 01 00 00 mov [esp+1E0h+var_98], esi
.text:10002D8E 89 B4 24 4C 01 00 00 mov [esp+1E0h+var_94], esi
.text:10002D95 89 B4 24 50 01 00 00 mov [esp+1E0h+var_90], esi
.text:10002D9C 89 84 24 54 01 00 00 mov [esp+1E0h+var_8C], eax
.text:10002DA3 E8 A8 EE FF FF call sub_10001C50
.text:10002DA3
.text:10002DA8
.text:10002DA8 loc_10002DA8: ; CODE XREF: key_verify+1B3j
.text:10002DA8 83 C4 08 add esp, 8
.text:10002DA8
.text:10002DAB
.text:10002DAB loc_10002DAB: ; CODE XREF: key_verify+14Ej
.text:10002DAB 8B 45 0C mov eax, [ebp+arg_4]
.text:10002DAE 8D 54 24 28 lea edx, [esp+1D8h+var_1B0]
.text:10002DB2 52 push edx
.text:10002DB3 57 push edi
.text:10002DB4 50 push eax
.text:10002DB5 53 push ebx
.text:10002DB6 E8 E5 F1 FF FF call sub_10001FA0 ; 返回值:0/失败, 1/成功
.text:10002DB6
.text:10002DBB 83 C4 10 add esp, 10h
.text:10002DBE F6 D8 neg al
.text:10002DC0 1B C0 sbb eax, eax
.text:10002DC2 25 FF FE FF FF and eax, 0FFFFFEFFh
.text:10002DC7 05 01 01 00 00 add eax, 101h ; 最后返回值:0/成功, 非0/失败
.text:10002DC7 ; 非0:0x101, 5, 2
.text:10002DCC 5F pop edi
.text:10002DCD 5E pop esi
.text:10002DCE 5B pop ebx
.text:10002DCF 8B E5 mov esp, ebp
.text:10002DD1 5D pop ebp
.text:10002DD2 C3 retn
.text:10002DD2
.text:10002DD3 ; ---------------------------------------------------------------------------
.text:10002DD3
.text:10002DD3 loc_10002DD3: ; CODE XREF: key_verify+6Cj
.text:10002DD3 ; key_verify+7Bj
.text:10002DD3 B8 05 00 00 00 mov eax, 5
.text:10002DD8 5F pop edi
.text:10002DD9 5E pop esi
.text:10002DDA 5B pop ebx
.text:10002DDB 8B E5 mov esp, ebp
.text:10002DDD 5D pop ebp
.text:10002DDE C3 retn
.text:10002DDE
.text:10002DDF ; ---------------------------------------------------------------------------
.text:10002DDF
.text:10002DDF loc_10002DDF: ; CODE XREF: key_verify+2Bj
.text:10002DDF 8B 3D 54 C2 01 10 mov edi, ds:Sleep
.text:10002DE5 BE 0A 00 00 00 mov esi, 0Ah
.text:10002DEA 8D 9B 00 00 00 00 lea ebx, [ebx+0]
.text:10002DEA
.text:10002DF0
.text:10002DF0 loc_10002DF0: ; CODE XREF: key_verify+255j
.text:10002DF0 6A 64 push 64h ; dwMilliseconds
.text:10002DF2 FF D7 call edi ; Sleep
.text:10002DF4 4E dec esi
.text:10002DF5 75 F9 jnz short loc_10002DF0
.text:10002DF5
.text:10002DF7
.text:10002DF7 loc_10002DF7: ; CODE XREF: key_verify+5Fj
.text:10002DF7 5F pop edi
.text:10002DF8 5E pop esi
.text:10002DF9 B8 02 00 00 00 mov eax, 2
.text:10002DFE 5B pop ebx
.text:10002DFF 8B E5 mov esp, ebp
.text:10002E01 5D pop ebp
.text:10002E02 C3 retn
.text:10002E02
.text:10002E02 key_verify endp
.text:10002E02
该函数同样分支众多,我们来一一解析。
第一部分
========
首先第一个可能导致函数返回非零值的分支出现在对函数sub_100025B0返回值的检查上--0/继续执行, 非0/sleep会儿然后返回2.
跟进函数sub_100025B0为:
.text:100025B0 sub_100025B0 proc near ; CODE XREF: key_verify+24p
.text:100025B0
.text:100025B0 var_4= dword ptr -4
.text:100025B0
.text:100025B0 53 push ebx
.text:100025B1 32 DB xor bl, bl
.text:100025B3 E8 B8 FF FF FF call sub_10002570
.text:100025B3
.text:100025B8 A1 A8 31 02 10 mov eax, off_100231A8
.text:100025BD 85 C0 test eax, eax
.text:100025BF 74 35 jz short loc_100025F6
.text:100025BF
.text:100025C1 B8 A8 31 02 10 mov eax, offset off_100231A8
.text:100025C6 56 push esi
.text:100025C7 8B F0 mov esi, eax
.text:100025C9 8D A4 24 00 00 00 00 lea esp, [esp+0]
.text:100025C9
.text:100025D0
.text:100025D0 loc_100025D0: ; CODE XREF: sub_100025B0+3Aj
.text:100025D0 8B 00 mov eax, [eax]
.text:100025D2 50 push eax ; char *
.text:100025D3 57 push edi ; char *
.text:100025D4 E8 87 38 00 00 call _strstr
.text:100025D4
.text:100025D9 83 C4 08 add esp, 8
.text:100025DC 85 C0 test eax, eax
.text:100025DE 75 11 jnz short loc_100025F1
.text:100025DE
.text:100025E0 8B 4E 04 mov ecx, [esi+4]
.text:100025E3 83 C6 04 add esi, 4
.text:100025E6 85 C9 test ecx, ecx
.text:100025E8 8B C6 mov eax, esi
.text:100025EA 75 E4 jnz short loc_100025D0
.text:100025EA
.text:100025EC 5E pop esi
.text:100025ED 8A C3 mov al, bl
.text:100025EF 5B pop ebx
.text:100025F0 C3 retn
.text:100025F0
.text:100025F1 ; ---------------------------------------------------------------------------
.text:100025F1
.text:100025F1 loc_100025F1: ; CODE XREF: sub_100025B0+2Ej
.text:100025F1 5E pop esi
.text:100025F2 B0 01 mov al, 1
.text:100025F4 5B pop ebx
.text:100025F5 C3 retn
.text:100025F5
.text:100025F6 ; ---------------------------------------------------------------------------
.text:100025F6
.text:100025F6 loc_100025F6: ; CODE XREF: sub_100025B0+Fj
.text:100025F6 8A C3 mov al, bl
.text:100025F8 5B pop ebx
.text:100025F9 C3 retn
.text:100025F9
.text:100025F9 sub_100025B0 endp
.text:100025F9
.text:100025F9 ; ---------------------------------------------------------------------------
可以看出函数在对一个字符串数组进行循环比对,如果用户输入的key值是该数组某个元素的字串的话返回非0,如果都不是则返回0.
那么这个数组是什么呢?进一步跟进发现该数组是个全局变量(在.data段中),数组每个元素所指的字符串也是全局变量,但均为乱码!!
这说明程序启动以后还会对该乱码进行变化以使其变为正常的字符串。那么必然有函数引用该全局数组!!果然我们看到除函数sub_100025B0
引用概述组外,还有一个函数sub_10002570对其进行了引用!
.data:100231A7 00 align 4
.data:100231A8 5C 31 02 10 off_100231A8 dd offset s_LmlmmkoN
.data:100231A8 ; DATA XREF: sub_10002570+9r
.data:100231A8 ; sub_10002570+19o
.data:100231A8 ; sub_100025B0+8r
.data:100231A8 ; sub_100025B0+11o
.data:100231A8 ; "媽媽寠廂嵑"
.data:100231AC 68 31 02 10 dd offset s_Lmlmmkokn ; "媽媽寠帄嵑"
.data:100231B0 74 31 02 10 dd offset s_Lkoknckilkglc ; "媻帄崡妶媻儖楕偤"
.data:100231B4 88 31 02 10 dd offset s_Lkoknckilgolc ; "媻帄崡妶媰帇楟孇嫼"
.data:100231B8 9C 31 02 10 dd offset s_Lmlmnkoknk ; "媽媽崐帄崐"
跳到该函数为:
.text:10002570 sub_10002570 proc near ; CODE XREF: sub_100025B0+3p
.text:10002570 A0 80 49 02 10 mov al, byte_10024980 ; xor
.text:10002575 84 C0 test al, al
.text:10002577 75 35 jnz short locret_100025AE
.text:10002577
.text:10002579 A1 A8 31 02 10 mov eax, off_100231A8
.text:1000257E 85 C0 test eax, eax
.text:10002580 C6 05 80 49 02 10 01 mov byte_10024980, 1
.text:10002587 74 25 jz short locret_100025AE
.text:10002587
.text:10002589 B8 A8 31 02 10 mov eax, offset off_100231A8
.text:1000258E 8B C8 mov ecx, eax
.text:1000258E
.text:10002590
.text:10002590 loc_10002590: ; CODE XREF: sub_10002570+3Cj
.text:10002590 8B 00 mov eax, [eax]
.text:10002592 80 38 00 cmp byte ptr [eax], 0
.text:10002595 74 0B jz short loc_100025A2
.text:10002595
.text:10002597
.text:10002597 loc_10002597: ; CODE XREF: sub_10002570+30j
.text:10002597 80 30 BA xor byte ptr [eax], 0BAh
.text:1000259A 8A 50 01 mov dl, [eax+1]
.text:1000259D 40 inc eax
.text:1000259E 84 D2 test dl, dl
.text:100025A0 75 F5 jnz short loc_10002597
.text:100025A0
.text:100025A2
.text:100025A2 loc_100025A2: ; CODE XREF: sub_10002570+25j
.text:100025A2 8B 51 04 mov edx, [ecx+4]
.text:100025A5 83 C1 04 add ecx, 4
.text:100025A8 85 D2 test edx, edx
.text:100025AA 8B C1 mov eax, ecx
.text:100025AC 75 E2 jnz short loc_10002590
.text:100025AC
.text:100025AE
.text:100025AE locret_100025AE: ; CODE XREF: sub_10002570+7j
.text:100025AE ; sub_10002570+17j
.text:100025AE C3 retn
.text:100025AE
.text:100025AE sub_10002570 endp
.text:100025AE
该函数比较简单,不再做详细解释。以下是我对该函数的逆向源代码:
#define FILTER_MAX 5
Byte g_byte1[] = {0x8B, 0x8C, 0x8B, 0x8C, 0x8C, 0x8A, 0x8E, 0xFB, 0x8D, 0xBA, 0x00};
Byte g_byte2[] = {0x8B, 0x8C, 0x8B, 0x8C, 0x8C, 0x8A, 0x8E, 0x8A, 0x8D, 0XBA, 0x00};
Byte g_byte3[] = {0x8B, 0x8A, 0x8E, 0x8A, 0x8D, 0x97, 0x8A, 0x88, 0x8B, 0x8A, 0x83,
0x8B, 0x97, 0xF8, 0xF8, 0xFE, 0x82, 0xBA, 0x00};
Byte g_byte4[] = {0x8B, 0x8A, 0x8E, 0x8A, 0x8D, 0x97, 0x8A, 0x88, 0x8B, 0x83, 0x8E,
0x8B, 0x97, 0xFE, 0x8B, 0xFE, 0x00};
Byte g_byte5[] = {0x8B, 0x8C, 0x8B, 0x8C, 0x8D, 0x8A, 0x8E, 0x8A, 0x8D, 0x8A, 0x00};
PBYTE g_strArray[] = {g_byte1, g_byte2, g_byte3, g_byte4, g_byte5, 0};
static void SetFilter()
{
int i=0, j=0;
PBYTE temp = NULL;
while (temp = g_strArray[i]) {
#ifdef _DEBUG
printf("Original value: ");
j = 0;
while (temp[j]) {
printf("0x%02X ", temp[j]);
j++;
}
printf("\n");
#endif
j = 0;
while (temp[j]) {
temp[j] ^= 0xBA;
j++;
}
#ifdef _DEBUG
printf("New value: %s\n\n", temp);
#endif
i++;
}
return;
}
通过运行该函数可以得到个字符串为:
Original value: 0x8B 0x8C 0x8B 0x8C 0x8C 0x8A 0x8E 0xFB 0x8D 0xBA
New value: 1616604A7
Original value: 0x8B 0x8C 0x8B 0x8C 0x8C 0x8A 0x8E 0x8A 0x8D 0xBA
New value: 161660407
Original value: 0x8B 0x8A 0x8E 0x8A 0x8D 0x97 0x8A 0x88 0x8B 0x8A 0x83 0x8B 0x97
0xF8 0xF8 0xFE 0x82 0xBA
New value: 10407-021091-BBD8
Original value: 0x8B 0x8A 0x8E 0x8A 0x8D 0x97 0x8A 0x88 0x8B 0x83 0x8E 0x8B 0x97
0xFE 0x8B 0xFE
New value: 10407-021941-D1D
Original value: 0x8B 0x8C 0x8B 0x8C 0x8D 0x8A 0x8E 0x8A 0x8D 0x8A
New value: 1616704070
因此输入的key值切不可为以上5个字符串中任何一个的字串!!!--不过话说回来真正想命中这些字串还是比较有难度的,所以我们可以不必
太在乎这个纸老虎。
第二部份
========
第二个分支发生在对函数sub_10002330调用完毕后进行返回值检查时:0/失败--返回2,非0/成功--继续执行。
下面对该函数进行详细讲解(其实该函数才是真正对Key进行变换验证的地方):
函数共有8个参数:除参数1为用户输入的key以外,其余参数均为局部变量地址--说明该函数需要将解析所得值填入这些局部变量!!
7个局部变量参数中,除参数2、3、5为指向DWORD型指针外,其余均为指向BYTE型指针!!
返回值只检查al--说明返回值类型也为BYTE型。
据此我们可以写出函数原型为:
call sub_10002330 ; Byte sub_10002330(pKey, pInt, pInt, pByte,
; pInt, pByte, pByte, pByte);
;
; 参数:1/pKey
;
; 返回值:0/失败,非0/成功
2.1 key_parse函数逆向
sub_10002330函数同样也是个拥有众多分支的函数,限于篇幅我把关键的几个地方的分析贴出来供大家参考:
.text:10002350 8D 54 24 64 lea edx, [esp+164h+field3]
.text:10002354 52 push edx ; field3
.text:10002355 8D 84 24 A8 00 00 00 lea eax, [esp+168h+field2]
.text:1000235C 50 push eax ; field2
.text:1000235D 8D 4C 24 2C lea ecx, [esp+16Ch+field1]
.text:10002361 51 push ecx ; field1
.text:10002362 8D 94 24 F0 00 00 00 lea edx, [esp+170h+key]
.text:10002369 52 push edx ; char *
.text:1000236A E8 E1 FE FF FF call key_parse ; 解析参数1所指字符串:****0407-******-****
.text:1000236A
同样key_parse也是我重命名的结果,大家可以参考地址找到原函数。该函数的作用是把用户输入的Key值按'-'字符分隔开,并把
每段字串地址的指针付给三个输入的指针参数。比如输入Key为10000407-123456-0512,分割后会变成"10000407","123456","0512"。
注意:该函数还对段数以及每段字串长度做了检查--第一段长度不得小于5,第二段长度必须为6,第三段长度必须为4!
以下是我对该函数的逆向源代码:
Byte key_parse (char *pKey, char *field1, char *field2, char *field3)
{
char *temp = NULL;
/* Field1 parse */
temp = strtok(pKey, "-");
if(temp==NULL || strlen(temp) < FIELD1_LEN_MIN)
return 0;
else
strcpy(field1, temp);
#ifdef _DEBUG
printf("\nfield1: %s", field1);
#endif
/* Field2 parse */
temp = strtok(NULL, "-");
if(temp==NULL || strlen(temp) != FIELD2_LEN)
return 0;
else
strcpy(field2, temp);
#ifdef _DEBUG
printf("\nfield2: %s", field2);
#endif
/* Field3 parse */
temp = strtok(NULL, "-");
if(temp==NULL || strlen(temp) != FIELD3_LEN)
return 0;
else
strcpy(field3, temp);
#ifdef _DEBUG
printf("\nfield3: %s", field3);
#endif
return 1;
}
2.2 sub_10002330函数逆向
经过上述解析后sub_10002330函数的逆向工作变得简单起来,重点部分我已经在注释中说明了:
.text:1000237A 8D 44 24 18 lea eax, [esp+158h+field1]
.text:1000237E 8D 50 01 lea edx, [eax+1]
.text:1000237E
.text:10002381
.text:10002381 loc_10002381: ; CODE XREF: sub_10002330+56j
.text:10002381 8A 08 mov cl, [eax]
.text:10002383 40 inc eax
.text:10002384 84 C9 test cl, cl
.text:10002386 75 F9 jnz short loc_10002381
.text:10002386
.text:10002388 2B C2 sub eax, edx
.text:1000238A 83 F8 05 cmp eax, 5 ; 再次比较field1长度>=5
.text:1000238D 0F 8C B0 01 00 00 jl loc_10002543
.text:1000238D
.text:10002393 56 push esi
.text:10002394 8D 74 04 18 lea esi, [esp+eax+15Ch+var_144]
.text:10002398 8D 54 24 0C lea edx, [esp+15Ch+var_150]
.text:1000239C 8B C6 mov eax, esi
.text:1000239E 2B D6 sub edx, esi
.text:1000239E
.text:100023A0
.text:100023A0 loc_100023A0: ; CODE XREF: sub_10002330+78j
.text:100023A0 8A 08 mov cl, [eax] ; field最后4个字节copy到var_150变量中去
.text:100023A2 88 0C 02 mov [edx+eax], cl
.text:100023A5 40 inc eax
.text:100023A6 84 C9 test cl, cl
.text:100023A8 75 F6 jnz short loc_100023A0
.text:100023A8
.text:100023AA 88 0E mov [esi], cl
.text:100023AC 80 7C 24 1C 2A cmp byte ptr [esp+15Ch+field1], 2Ah ; '*'
.text:100023B1 75 0F jnz short loc_100023C2
.text:100023B1
.text:100023B3 8B 84 24 68 01 00 00 mov eax, [esp+15Ch+arg_8]
.text:100023BA C7 00 FF FF FF FF mov dword ptr [eax], 0FFFFFFFFh
.text:100023C0 EB 1D jmp short loc_100023DF
.text:100023C0
.text:100023C2 ; ---------------------------------------------------------------------------
.text:100023C2
.text:100023C2 loc_100023C2: ; CODE XREF: sub_10002330+81j
.text:100023C2 6A 0A push 0Ah ; int
.text:100023C4 8D 4C 24 0C lea ecx, [esp+160h+var_154]
.text:100023C8 51 push ecx ; char **
.text:100023C9 8D 54 24 24 lea edx, [esp+164h+field1]
.text:100023CD 52 push edx ; char *
.text:100023CE E8 2F 39 00 00 call _strtol ; field1头4个字节转为long
.text:100023CE
.text:100023D3 8B 8C 24 74 01 00 00 mov ecx, [esp+168h+arg_8]
.text:100023DA 83 C4 0C add esp, 0Ch
.text:100023DD 89 01 mov [ecx], eax ; 结果赋值参数3所指变量
.text:100023DD
.text:100023DF
.text:100023DF loc_100023DF: ; CODE XREF: sub_10002330+90j
.text:100023DF 8A 54 24 0C mov dl, byte ptr [esp+15Ch+var_150]
.text:100023E3 8A 44 24 0D mov al, byte ptr [esp+15Ch+var_150+1]
.text:100023E7 6A 10 push 10h ; int
.text:100023E9 8D 4C 24 0C lea ecx, [esp+160h+var_154]
.text:100023ED 88 54 24 1C mov [esp+160h+var_144], dl
.text:100023F1 51 push ecx ; char **
.text:100023F2 8D 54 24 20 lea edx, [esp+164h+var_144]
.text:100023F6 52 push edx ; char *
.text:100023F7 88 44 24 25 mov [esp+25h], al ; field1倒数第3个字节
.text:100023F7 ; 存放到栈变量中
.text:100023FB C6 44 24 26 00 mov byte ptr [esp+26h], 0
.text:10002400 E8 14 39 00 00 call _strtoul ; field1倒数第4,3个字节
.text:10002400 ; 按16进制转为long
.text:10002400
.text:10002405 8B 8C 24 78 01 00 00 mov ecx, [esp+168h+arg_C]
.text:1000240C 8B 54 24 14 mov edx, [esp+168h+var_154]
.text:10002410 88 01 mov [ecx], al ; 结果赋值参数4所指变量
.text:10002412 8A 02 mov al, [edx]
.text:10002414 83 C4 0C add esp, 0Ch
.text:10002417 84 C0 test al, al
.text:10002419 0F 85 2E 01 00 00 jnz loc_1000254D
.text:10002419
.text:1000241F 8A 44 24 0E mov al, byte ptr [esp+15Ch+var_150+2] ; field1倒数第2个字节
.text:10002423 8A 4C 24 0F mov cl, byte ptr [esp+15Ch+var_150+3] ; 最后个
.text:10002427 6A 10 push 10h ; int
.text:10002429 8D 54 24 0C lea edx, [esp+160h+var_154]
.text:1000242D 88 44 24 18 mov [esp+160h+var_148], al
.text:10002431 52 push edx ; char **
.text:10002432 8D 44 24 1C lea eax, [esp+164h+var_148]
.text:10002436 50 push eax ; char *
.text:10002437 88 4C 24 21 mov [esp+21h], cl ; 最后个字节存放栈变量
.text:1000243B C6 44 24 22 00 mov byte ptr [esp+22h], 0
.text:10002440 E8 D4 38 00 00 call _strtoul ; 倒数后2个字节按16进制long
.text:10002440
.text:10002445 8B 4C 24 14 mov ecx, [esp+168h+var_154]
.text:10002449 8A 11 mov dl, [ecx]
.text:1000244B 83 C4 0C add esp, 0Ch
.text:1000244E 84 D2 test dl, dl
.text:10002450 0F 85 F7 00 00 00 jnz loc_1000254D
.text:10002450
.text:10002456 8B B4 24 70 01 00 00 mov esi, [esp+15Ch+arg_10] ; 参数5
.text:1000245D 8B 9C 24 7C 01 00 00 mov ebx, [esp+15Ch+arg_1C] ; 参数8
.text:10002464 33 D2 xor edx, edx
.text:10002466 8A D0 mov dl, al
.text:10002468 8A C8 mov cl, al
.text:1000246A 80 E1 20 and cl, 20h
.text:1000246D 55 push ebp
.text:1000246E 8B AC 24 7C 01 00 00 mov ebp, [esp+160h+arg_18] ; 参数7
.text:10002475 57 push edi
.text:10002476 8B BC 24 7C 01 00 00 mov edi, [esp+164h+arg_14] ; 参数6
.text:1000247D 83 E2 1F and edx, 1Fh
.text:10002480 80 F9 20 cmp cl, 20h
.text:10002483 89 16 mov [esi], edx ; 转换结果&0x1F
.text:10002483 ; 存放到参数5所指变量
.text:10002485 0F 94 C2 setz dl
.text:10002488 8A C8 mov cl, al
.text:1000248A 80 E1 40 and cl, 40h
.text:1000248D 88 17 mov [edi], dl ; 转换结果与&0x20
.text:1000248D ; 结果赋值参数6所指变量
.text:1000248F 80 F9 40 cmp cl, 40h
.text:10002492 0F 94 C2 setz dl
.text:10002495 24 80 and al, 80h
.text:10002497 88 55 00 mov [ebp+0], dl ; 转换结果与&0x40
.text:10002497 ; 结果赋值参数7所指变量
.text:1000249A 6A 0A push 0Ah ; int
.text:1000249C 8D 4C 24 14 lea ecx, [esp+168h+var_154]
.text:100024A0 3C 80 cmp al, 80h
.text:100024A2 51 push ecx ; char **
.text:100024A3 8D 94 24 AC 00 00 00 lea edx, [esp+16Ch+field2]
.text:100024AA 0F 94 C0 setz al
.text:100024AD 52 push edx ; char *
.text:100024AE 88 03 mov [ebx], al ; 转换结果与&0x80
.text:100024AE ; 结果赋值参数8所指变量
.text:100024AE ;
.text:100024B0 E8 4D 38 00 00 call _strtol ; field2按10进制转为long
.text:100024B0
.text:100024B5 8B 8C 24 78 01 00 00 mov ecx, [esp+170h+arg_4]
.text:100024BC 8B 54 24 1C mov edx, [esp+170h+var_154]
.text:100024C0 89 01 mov [ecx], eax ; 结果赋值参数2所指变量
.text:100024C2 8A 02 mov al, [edx]
.text:100024C4 83 C4 0C add esp, 0Ch
.text:100024C7 84 C0 test al, al
.text:100024C9 0F 85 89 00 00 00 jnz loc_10002558
.text:100024C9
.text:100024CF 6A 10 push 10h ; int
.text:100024D1 8D 44 24 14 lea eax, [esp+168h+var_154]
.text:100024D5 50 push eax ; char **
.text:100024D6 8D 4C 24 6C lea ecx, [esp+16Ch+field3]
.text:100024DA 51 push ecx ; char *
.text:100024DB E8 39 38 00 00 call _strtoul ; field3转为16进制
.text:100024DB
.text:100024E0 8B 54 24 1C mov edx, [esp+170h+var_154]
.text:100024E4 89 44 24 20 mov [esp+170h+var_150], eax ; 结果赋值变量var_150
.text:100024E8 8A 02 mov al, [edx]
.text:100024EA 83 C4 0C add esp, 0Ch
.text:100024ED 84 C0 test al, al
.text:100024EF 75 67 jnz short loc_10002558
.text:100024EF
.text:100024F1 33 C0 xor eax, eax
.text:100024F3 8A 03 mov al, [ebx] ; 原参数8所指字节
.text:100024F5 33 C9 xor ecx, ecx
.text:100024F7 8A 4D 00 mov cl, [ebp+0] ; 原参数7所指字节
.text:100024FA 33 D2 xor edx, edx
.text:100024FC 8A 17 mov dl, [edi] ; 原参数6所指字节
.text:100024FE 50 push eax
.text:100024FF 8B 06 mov eax, [esi]
.text:10002501 51 push ecx
.text:10002502 8B 8C 24 7C 01 00 00 mov ecx, [esp+16Ch+arg_C]
.text:10002509 52 push edx
.text:1000250A 33 D2 xor edx, edx
.text:1000250C 8A 11 mov dl, [ecx]
.text:1000250E 50 push eax ; 原参数5所指Int
.text:1000250F 8B 84 24 80 01 00 00 mov eax, [esp+174h+arg_8]
.text:10002516 8B 08 mov ecx, [eax]
.text:10002518 52 push edx ; 原参数4所指字节
.text:10002519 8B 94 24 80 01 00 00 mov edx, [esp+178h+arg_4]
.text:10002520 8B 02 mov eax, [edx]
.text:10002522 51 push ecx ; 原参数3所指Int
.text:10002522 ; field1头4个字节
.text:10002522 ; strtol转换结果
.text:10002523 50 push eax ; 原参数2所指Int
.text:10002523 ; strtol(field2)
.text:10002524 E8 97 FC FF FF call sub_100021C0 ; func(arg2, arg3, arg4, arg5, arg6, arg7, arg8)
.text:10002524
.text:10002529 83 C4 1C add esp, 1Ch
.text:1000252C 0F B7 C8 movzx ecx, ax
.text:1000252F 8B 44 24 14 mov eax, [esp+164h+var_150]
.text:10002533 5F pop edi
.text:10002534 5D pop ebp
.text:10002535 3B C1 cmp eax, ecx
.text:10002537 5E pop esi
.text:10002538 0F 94 C0 setz al
.text:1000253B 5B pop ebx
.text:1000253C 81 C4 54 01 00 00 add esp, 154h
.text:10002542 C3 retn
.text:10002542
.text:10002543 ; ---------------------------------------------------------------------------
.text:10002543
.text:10002543 loc_10002543: ; CODE XREF: sub_10002330+5Dj
.text:10002543 32 C0 xor al, al
.text:10002545 5B pop ebx
.text:10002546 81 C4 54 01 00 00 add esp, 154h
.text:1000254C C3 retn
.text:1000254C
.text:1000254D ; ---------------------------------------------------------------------------
.text:1000254D
.text:1000254D loc_1000254D: ; CODE XREF: sub_10002330+E9j
.text:1000254D ; sub_10002330+120j
.text:1000254D 5E pop esi
.text:1000254E 32 C0 xor al, al
.text:10002550 5B pop ebx
.text:10002551 81 C4 54 01 00 00 add esp, 154h
.text:10002557 C3 retn
.text:10002557
.text:10002558 ; ---------------------------------------------------------------------------
.text:10002558
.text:10002558 loc_10002558: ; CODE XREF: sub_10002330+199j
.text:10002558 ; sub_10002330+1BFj
.text:10002558 5F pop edi
.text:10002559 5D pop ebp
.text:1000255A 5E pop esi
.text:1000255B 32 C0 xor al, al
.text:1000255D 5B pop ebx
.text:1000255E 81 C4 54 01 00 00 add esp, 154h
.text:10002564 C3 retn
.text:10002564
.text:10002565 ; ---------------------------------------------------------------------------
.text:10002565
.text:10002565 loc_10002565: ; CODE XREF: sub_10002330+44j
.text:10002565 8A C3 mov al, bl
.text:10002567 5B pop ebx
.text:10002568 81 C4 54 01 00 00 add esp, 154h
.text:1000256E C3 retn
.text:1000256E
.text:1000256E sub_10002330 endp
.text:1000256E
下面给出该函数的逆向源代码:
#define KEYBUF_LEN 0x80
#define FIELD_BUF_LEN 0x40
#define OTHER_BUF_LEN 0x08
Byte sub_10002330(char *pKey, int *pArg2, int *pArg3,
PBYTE pArg4, int *pArg5, PBYTE pArg6, PBYTE pArg7, PBYTE pArg8)
{
char key_buf[KEYBUF_LEN], field1_buf[FIELD_BUF_LEN];
char field2_buf[FIELD_BUF_LEN], field3_buf[FIELD_BUF_LEN];
int var_144=0, var_148=0;
char other_buf[OTHER_BUF_LEN], *pEndPtr;
int len = 0;
Byte rc = 0, tmp = 0;
strncpy(key_buf, pKey, KEYBUF_LEN);
if (key_parse(key_buf, field1_buf, field2_buf, field3_buf) == 0) {
/* key_parse failed: return 0 */
return rc;
}
if ((len = strlen(field1_buf)) < 5) {
return rc;
}
strcpy(other_buf, &field1_buf[len-4]);
field1_buf[len-4] = '\0';
if (field1_buf[0] == '*')
*pArg3 = -1;
else {
*pArg3 = strtol(field1_buf, &pEndPtr, 0x0A);
}
((char *)&var_144)[0] = other_buf[0];
((char *)&var_144)[1] = other_buf[1];
*pArg4 = (Byte) strtol((char *)&var_144, &pEndPtr, 0x10);
if (*pArg4 == 0)
return rc;
((char *)&var_148)[0] = other_buf[2];
((char *)&var_148)[1] = other_buf[3];
tmp = (Byte) strtol((char *)&var_148, &pEndPtr, 0x10);
if (*pEndPtr != NULL)
return rc;
*pArg5 = tmp & 0x1F;
*pArg6 = tmp & 0x20;
*pArg7 = tmp & 0x40;
*pArg8 = tmp & 0x80;
*pArg2 = strtol(field2_buf, &pEndPtr, 0x0A);
if (*pEndPtr != NULL)
return rc;
var_144 = strtol(field3_buf, &pEndPtr, 0x10);
if(*pEndPtr != NULL)
return rc;
var_148 = sub_100021C0(*pArg2, *pArg3, *pArg4, *pArg5, *pArg6, *pArg7, *pArg8);
if ((var_148 & 0xFFFF) == var_144)
rc = 1;
#ifdef _DEBUG
printf("%s(%d): return value %d\n", rc);
#endif
return rc;
}
声明:其中几个变量使用没有严格按照汇编代码翻译,而是做了多用途使用:var_144, var_148。
2.3 sub_100021C0函数逆向
该函数是函数sub_10002330调用的最后一个函数,其返回值直接决定sub_10002330函数的最后成败。
下面给出对该函数的分析:
返回值:ax--WORD型值
参数:共7个,观察得到为sub_10002330函数参数2-8指针所指向的变量值!
这些变量在调用sub_100021C0函数之前已经被赋予了值--具体参见2.2。
下面给出对该函数的逆向:
#define BUF_LEN 9
unsigned sub_100021C0 (int arg1, int arg2, Byte arg3, int arg4, Byte arg5, Byte arg6, Byte arg7)
{
unsigned buf[BUF_LEN] = {
arg1, ~arg1, arg2, ~arg2,
(unsigned)arg3, arg4,
(unsigned)arg5, (unsigned)arg6,
(unsigned)arg7
};
unsigned result;
result = sub_10004070((PBYTE)buf, sizeof(buf));
result = (result >> 16) ^ result;
#ifdef _DEBUG
printf("%s(%d)--result=%08X\n", __FILE__, __LINE__, result);
#endif
return result;
}
其中sub_10004070函数在程序中多处用到(后面注册表键值修改时还要用到),这里也给出对其的逆向:
#define XOR_SEED 0x1021
#define INNER_LOOP_MAX 7
int sub_10004070 (PBYTE buf, unsigned len)
{
int result=0xB0BAB0BA, temp = 0;
unsigned i=0, j=0;
if (len <= 0 )
return result;
while (i<len) {
temp = (int) (char)buf[i];
result ^= (temp << 8);
j = 0;
while (j++ < INNER_LOOP_MAX) {
if (result < 0) {
result = (result << 1) ^ XOR_SEED;
}
else
result <<= 1;
}
i++;
}
#ifdef _DEBUG
printf("\n%s(%d)--result=%08X\n", __FILE__, __LINE__, result);
#endif
return result;
}
2.4 计算返回值
就像2.2给出的源代码所示,程序用field3字段转化后的结果与sub_100021C0函数返回值比较--相等返回1(成功),不相等返回0(失败)。
第三部分--修改注册表键值
===========
上述两部分都正确执行以后就可以正确注册了,key_verify函数剩下的工作就是修改注册表以便下次启动能判断出是否已经注册过了。
本部分工作相对不这么重要,读者可自行分析。下面给出相关的几个函数逆向:
#ifdef _DEBUG
#define COLUM_LEN 8
static void DebugPrint(char *pTitle, PBYTE pData, int nDataLen)
{
int i = 0, j, temp;
printf("\n%s\n", pTitle);
printf("=====\n");
for (; i<nDataLen/COLUM_LEN; i++) {
printf("%08x: ", i);
temp = i<<3;
for (j=0; j<COLUM_LEN; j++)
printf("%02X ", pData[temp+j]);
printf("\n");
}
if (nDataLen % COLUM_LEN) {
printf("%08x: ", i);
temp = i<<3;
for (temp = i<<3; temp<nDataLen; temp++)
printf("%02X ", pData[temp]);
printf("\n");
}
}
#endif
static void RegKeyProcess(PBYTE pData, int nDataLen, DWORD seed)
{
int i=0, temp;
if (nDataLen<=0)
return;
for (; i<nDataLen; i+=4) {
temp = seed >> 31;
seed += seed;
temp |= seed;
seed = (i >> 2) ^ temp;
*(DWORD *)&pData[i] ^= seed;
}
#ifdef _DEBUG
DebugPrint("RegValue after process", (PBYTE)pData, nDataLen);
#endif
return;
}
#define VALUE_BUF_LEN 0x80
#define REGDATA_LEN 0x1AC
Byte sub_10001D40 (char *pProgramFile, int arg2, int arg3, char *pOutPut)
{
char ValueName[VALUE_BUF_LEN];
HGLOBAL pData;
HKEY hKey;
DWORD cbData = REGDATA_LEN, type = 3;
LONG rc = ERROR_SUCCESS;
int temp;
Byte result = 0;
sprintf(ValueName, "%s (%d-%02X)", pProgramFile,
(arg3 ^ (~0x55A) & 0XFFF), (arg2 ^ 0xBA));
temp = sub_10004070((PBYTE)ValueName, strlen(ValueName));
#ifdef _DEBUG
printf("\nValueName: %s, len=%d\n", ValueName, strlen(ValueName));
#endif
pData = GlobalAlloc(0, REGDATA_LEN);
RegOpenKeyEx(HKEY_CURRENT_USER, BREAK_LICENSE_MANAGER, 0, 0x20019, &hKey);
RegQueryValueEx(hKey, ValueName, 0, &type, (PBYTE)pData, &cbData);
#ifdef _DEBUG
DebugPrint(ValueName, (PBYTE)pData, cbData);
#endif
if (cbData == REGDATA_LEN) {
RegKeyProcess((PBYTE)pData, cbData, temp);
memcpy(pOutPut, pData, REGDATA_LEN);
temp = *(DWORD *)&pOutPut[0x1A8];
*(DWORD *)&pOutPut[0x1A8] = 0x0AC1DBA5E;
rc = sub_10004070((PBYTE)pOutPut, REGDATA_LEN);
*(DWORD *)&pOutPut[0x1A8] = temp;
if (temp == rc)
result = 1;
#ifdef _DEBUG
printf("%s(%d): result is %d\n", __FILE__, __LINE__, result);
#endif
}
RegCloseKey(hKey);
GlobalFree(pData);
return result;
}
到这里Hex Workshop V4.2加密算法部分的逆向基本完成了。注册表部分还是很有乐趣的,我这里限于篇幅没有做过多介绍--其实因为
文笔是在太烂了:).
--------------------------------------------------------------------------------
【经验总结】
1、关于本软件
用户输入Key值需如下格式:****04$7-******-****
其中第一个字段必须长度>=5(我采用了8个字节长), 第二、三字段长度分为6,4。
字段1会被解析成6个值,字段2按照16进制转为long型,字段3按照10进制转为long型。
字段1的6个值和字段2的值作为参数经过函数sub_100021C0运算后的返回值与字段3比较,相等则认为输入的Key正确,否则
返回错误。
2、关于MFC程序
1- 查找注册资源(如果有该资源的话)
2- 通过基类构造函数判断出正确的虚函数表
3- 通过相关虚函数或者AFX_MSG_ENTRY找到相应按钮处理函数
4- 如果有输入,可以通过重载的DoDataExchange静态分析出相应数据成员
进而可以进行算法分析了。
最后我采用的注册码为:10000407-123456-5162
所谓的虚拟技术就是为代码技术,那个如果被找到规律的话就好像直接源代码暴露于眼前一样。。
【 在 rebirthatsix 的大作中提到: 】
: 恩,挺好的,虽然现在虚拟机横行
多是一种单身加密技术,所谓的多态变形。
加密后是1对1
还原后是1对多
规则很难找,看到就头疼。
【 在 Dark (The Star of Darkness) 的大作中提到: 】
: 所谓的虚拟技术就是为代码技术,那个如果被找到规律的话就好像直接源代码暴露于眼前一样。。
【 在 Dark 的大作中提到: 】
: 所谓的虚拟技术就是为代码技术,那个如果被找到规律的话就好像直接源代码暴露于眼前一样。。
昂?兄台莫非就是传说可以肉眼还原vmp或者themida的强人