作 者: qiweixue
时 间: 2006-09-23,19:48
链 接: http://bbs.pediy.com/showthread.PHP?t=32356
高中物理课件是中学生学习物理之必备...
软件采用了次数限制使用超过三次,跳出提示注册的Nag并且打开官方网站要求注册,其次软件注册是计算一个本地机器码,根据本地机器码运算加密.
官方网站:http://www.flztgzsh.ys168.com/
高中物理课件全集(2005.08版),好像是在wwww.skycn.net或者是在华军下载的..
下边给出破解分析次数和Nag,还有注册分析流程...有错误之处谢谢指正.
1:罗列一下vb调用约定,有助于分析.2:分析VB调用一个SDK API(GetVolumeInformationA)过程来计算机器码和它的参数Unicode转变Ansi化,并且通MSVBVM60.DllFunctionCall调用SDK API. 3:分析破解次数流程和nag窗体,4:分析注册算法过程.
VB函数约定太杂乱没有统一性,自己分析了几个函数:有的用eax,edx约定,有的单个ecx约定,有的堆栈、寄存器一起用,有的象stdcall约定,有时候会跟虚拟机内部组件传地址引用.
先给出函数分析,下边分析汇编的时候,可以看这些函数,不是很全的且存在错误.仅仅供参考.大家可以一起补充.
-----------------------------------------------------------------
MSVBVM60.__vbaObjSet类似MSVBVM60.__vbanew2用来给对象赋值或者实例化
类似stdcall
push eax----->类对象模版地址
lea eax,[ebp-1C]
push eax-------->欲要设置引用对象指针给eax
call 401048 ---> MSVBVM60.__vbaObjSet
--------------------------------------------------
在每个事件触发之前都要调用MSVBVM60.Zombie_AddRef来记数
事件引用的COM组件对象.约定eax,ecx
mov eax,esi
and eax,1
mov [ebp-4],eax
and esi,FFFFFFFE------>经过这寻址正好是对象虚拟表指针
push esi------>保存对象虚表指针esi
mov [ebp+8],esi---->esi被局部变量保存[ebp+8]
mov ecx,[esi]----->对象虚拟表地址给ecx
call [ecx+4] ---------> MSVBVM60.Zombie_AddRef
--------------------------------------------------
在每个事件结束之后都后调用MSVBVM60.Zombie_Release来
释放事件引用的COM组件对象,约定eax.
MSVBVM60.Zombie_Release释放对象约定参数寄存器:eax
mov eax,[ebp+8]
push eax-----------对象地址eax
mov edx,[eax]----->对象虚拟表地址给edx
call [edx+8] -----> MSVBVM60.Zombie_Release
-------------------------------------------------------------------
MSVBVM60.__vbaFreeObj释放对象约定寄存器:ecx
lea ecx,[ebp-24]--->对象引用指针ecx
call [401140] --->MSVBVM60.__vbaFreeObj
--------------------------------------------------
MSVBVM60.__vbaChkstk调整堆栈指针约定寄存器:eax
mov eax,10
call 004016C0---->MSVBVM60.__vbaChkstk--->这个函数返回的时候就是把esp+10
---------------------------------------------------
MSVBVM60.__vbaNew2类似C++/JAVA的new函数
push 0043E120--->对象地址
push 004031A4---------->类模版地址
call 4010E0 ---> MSVBVM60.__vbaNew2
----------------------------------------------------
MSVBVM60.__vbaStrMove 是寄存器约定 edx和ecx.
mov edx,eax---->UNICODE字符串源地址:edx
lea ecx,[ebp-24]---->UNICODE字符串目的地址:ecx
call 401120 ----> MSVBVM60.__vbaStrMove
-----------------------------------------------------
MSVBVM60.__vbaStrCat 是stdcall约定
push edx----->连接目的UNICODE字符串
push 00@R_403_448@230 ---->UNICODE字符串常量
call 401034 ---->MSVBVM60.__vbaStrCat
-----------------------------------------------------
MSVBVM60.__vbaFreeStr 约定寄存器:ecx
lea ecx,[ebp-24]--->ecx传字符串引用
call 40113C----> MSVBVM60.__vbaFreeStr
-----------------------------------------------------
MSVBVM60.__vbaFreeStrList是可变参数Cdcall约定
lea eax,[ebp-28]--->UNICODE字符串引用地址eax
push eax
lea ecx,[ebp-24]---->UNICODE字符串引用地址ecx
push ecx
push 2------->释放2个UNICODE字符串
call 4010F0 ---> MSVBVM60.__vbaFreeStrList
add esp,0C
-----------------------------------------------------
MSVBVM60.__vbaFileOpen是Cdcall约定
push eax---->UNICODE文件字符串名称
push 1
push -1
push 1
call 4010F0-----> MSVBVM60.__vbaFileOpen
add esp,0C
----------------------------------------------------
分析程序提取本地机器码
字符串常量: const string_00403FDC="c:\"
机器码全局变量 :int_[43E108] 保存机器码
004108FB . BA DC3F4000 mov edx,00403FDC----> UNICODE字符号常量 "c:\"
00410900 . 8D4D DC lea ecx,[ebp-24]
00410903 . FF15 EC104000 call [<&MSVBVM60.__vbaStrCopy>]--->见上边
00410909 . 8D55 DC lea edx,[ebp-24]
0041090C . 52 push edx------->UNICODE字符串参数="c:\"
0041090D . E8 AEF9FFFF call 004102C0---------->关键Call:获取机器码函数
00410912 . A3 08E14300 mov [43E108],eax--->返回值通过eax给机器码全局变量
call 004102C0 (int edx)过程如下:
004102C0 $ 55 push ebp
004102C1 . 8BEC mov ebp,esp
004102C3 . 83EC 08 sub esp,8
004102C6 . 68 C6164000 push <jmp.&MSVBVM60.__vbaExceptHandler>
004102CB . 64:A1 0000000>mov eax,fs:[0]
004102D1 . 50 push eax
004102D2 . 64:8925 00000>mov fs:[0],esp
004102D9 . 83EC 40 sub esp,40
004102DC . 53 push ebx
004102DD . 56 push esi
004102DE . 57 push edi
004102DF . 8965 F8 mov [ebp-8],esp
004102E2 . C745 FC 50114>mov dword ptr [ebp-4],00401150
004102E9 . 8B3D D0104000 mov edi,[<&MSVBVM60.#537>]
004102EF . 33F6 xor esi,esi
004102F1 . 56 push esi
004102F2 . 8975 E8 mov [ebp-18],esi ----->[ebp-18]___[12FC54]===lpVolumeSerialNumber
004102F5 . 8975 E4 mov [ebp-1C],esi ; [12FC50]
004102F8 . 8975 E0 mov [ebp-20],esi ; [12FC4C]
004102FB . 8975 D8 mov [ebp-28],esi ; [12FC44]
004102FE . 8975 D4 mov [ebp-2C],esi ; [12FC40]
00410301 . 8975 D0 mov [ebp-30],esi ; [12FC3C]
00410304 . 8975 C0 mov [ebp-40],esi ; [12FC2C]
00410307 . 8975 BC mov [ebp-44],esi ----->[Ebp-44]___[12FC28]====lpMaximumComponentLength参数
0041030A . 8975 B8 mov [ebp-48],esi ----> [ebp-48]__[12FC24]====lpFileSystemFlags
0041030D . FFD7 call edi
0041030F . 8B1D BC104000 mov ebx,[<&MSVBVM60.#606>] --> MSVBVM60.rtcStringBstr
00410315 . 8945 C8 mov [ebp-38],eax ---> [ebp-38]=12FC34
00410318 . 8D45 C0 lea eax,[ebp-40]-->[ebp-40] [12FC2C]
0041031B . C745 C0 08000>mov dword ptr [ebp-40],8
00410322 . 50 push eax
00410323 . 68 FF000000 push 0FF
00410328 . FFD3 call ebx
0041032A . 8BD0 mov edx,eax
0041032C . 8D4D E4 lea ecx,[ebp-1C] ------->[ebp-1C]=[12FC50]
0041032F . FF15 20114000 call [<&MSVBVM60.__vbaStrMove>]
00410335 . 8D4D C0 lea ecx,[ebp-40] ------>[ebp-40] =[12FC2C]
00410338 . FF15 10104000 call [<&MSVBVM60.__vbaFreeVar>]
0041033E . 56 push esi
0041033F . FFD7 call edi
00410341 . 8D4D C0 lea ecx,[ebp-40] ----> [ebp-40]=[12FC2C]
00410344 . 8945 C8 mov [ebp-38],eax ---->eax=0014FAFC--->lpRootPathName
00410347 . 51 push ecx
00410348 . 68 FF000000 push 0FF
0041034D . C745 C0 08000>mov dword ptr [ebp-40],8 ------->[ebp-40]=[12FC2C]
00410354 . FFD3 call ebx
00410356 . 8BD0 mov edx,eax ----->eax=0014FE74
00410358 . 8D4D E0 lea ecx,[ebp-20] ----> [ebp-20]=[12FC4C]
0041035B . FF15 20114000 call [<&MSVBVM60.__vbaStrMove>] ---> MSVBVM60.__vbaStrMove
00410361 . 8D4D C0 lea ecx,[ebp-40] ; 0012FC2C
00410364 . FF15 10104000 call [<&MSVBVM60.__vbaFreeVar>] ---> MSVBVM60.__vbaFreeVar
0041036A . 8B55 E0 mov edx,[ebp-20] ; [12FC4C]
0041036D . 8B3D 1C104000 mov edi,[<&MSVBVM60.__vbaLenBstr>] ----> MSVBVM60.__vbaLenBstr
00410373 . 52 push edx
00410374 . 8975 B8 mov [ebp-48],esi ---------->0012FC24_lpFileSystemFlags
00410377 . 8975 BC mov [ebp-44],esi ------>0012FC28_lpMaximumComponentLength
0041037A . FFD7 call edi ; <&MSVBVM60.__vbaLenBstr>
0041037C . 8B35 10114000 mov esi,[<&MSVBVM60.__vbaStrToAnsi>]--->MSVBVM60.__vbaStrToAnsi
00410382 . 50 push eax--------------------------------->eax=FF=nFileSystemNameSize入栈
00410383 . 8B45 E0 mov eax,[ebp-20]--->[ebp-20]=[12FC4C]
00410386 . 8D4D D0 lea ecx,[ebp-30] --> [ebp-20]=[12FC3C]
00410389 . 50 push eax
0041038A . 51 push ecx
0041038B . FFD6 call esi ------><&MSVBVM60.__vbaStrToAnsi>
0041038D . 50 push eax------------------------->0015009C--->lpFileSystemNameBuffer入栈
0041038E . 8D55 B8 lea edx,[ebp-48]---------->edx=12FC24_lpFileSystemFlags
00410391 . 8D45 BC lea eax,[ebp-44]------>eax=0012FC28=lpMaximumComponentLength
00410394 . 52 push edx --------->edx=0012FC24=lpFileSystemFlags
00410395 . 8B55 E4 mov edx,[ebp-1C] ; 12FC50
00410398 . 8D4D E8 lea ecx,[ebp-18]--->ecx=12FC54_lpVolumeSerialNumber
0041039B . 50 push eax-------------------------->0012FC28=lpMaximumComponentLength入栈
0041039C . 51 push ecx------------------------------>0012FC54=lpVolumeSerialNumber入栈
0041039D . 52 push edx--------------------------------->0012FC24=lpFileSystemFlags入栈
0041039E . FFD7 call edi--->------><&MSVBVM60.__vbaStrToAnsi>
004103A0 . 8BC8 mov ecx,eax-->FF
004103A2 . FF15 84104000 call [<&MSVBVM60.__vbaI2I4>]
004103A8 . 50 push eax-----------------------------------> 000000FF=nVolumeNameSize入栈
004103A9 . 8B45 E4 mov eax,[ebp-1C] ---> 12FC50
004103AC . 8D4D D4 lea ecx,[ebp-2C] ---> 12FC50
004103AF . 50 push eax
004103B0 . 51 push ecx
004103B1 . FFD6 call esi ------><&MSVBVM60.__vbaStrToAnsi>
004103B3 . 8B7D 08 mov edi,[ebp+8]--->12FC74
004103B6 . 50 push eax--------------------------------->001501C4=lpVolumeNameBuffer入栈
004103B7 . 8D45 D8 lea eax,[ebp-28] --> [ebp-28]=12FC44
004103BA . 8B17 mov edx,[edi] --->0012FD70
004103BC . 52 push edx -->0014F92C C:\
004103BD . 50 push eax -->0012FC44
004103BE . FFD6 call esi ------><&MSVBVM60.__vbaStrToAnsi>
004103C0 . 50 push eax------------------------------------>0014FAFC_lpRootPathName入栈
004103C1 . E8 D23BFFFF call 00403F98----------->关键call,虽然它参数全部Ansi化了,但还没有调用但还没有调用GetVolumeInformation请看下边分析
--------------------------------------------------------------------------------------------------------
stdcall方式,参数由Unicode转化为Ansi看堆栈:
0012FBF0 0014FAFC--->lpRootPathName
0012FBF4 001501C4--->lpVolumeNameBuffer
0012FBF8 000000FF--->nVolumeNameSize
0012FBFC 0012FC54---->lpVolumeSerialNumber
0012FC00 0012FC28---->lpMaximumComponentLength
0012FC04 0012FC24--->lpFileSystemFlags
0012FC08 0015009C--->lpFileSystemNameBuffer
0012FC0C 000000FF--->nFileSystemNameSize
继续分析从上边call 00403F9 进入
00403F98 $ A1 0CE54300 mov eax,[43E50C]--->[43E50C]保存GetVolumeInformationA函数地址
00403F9D . 0BC0 or eax,eax--->地址为空就跳
00403F9F . 74 02 je short 00403FA3
00403FA1 . FFE0 jmp eax
00403FA3 > 68 803F4000 push 00403F80--->关键地址:00403F54数值地址看下边
00403FA8 . B8 50174000 mov eax,401750----->MSVBVM60.DllFunctionCall地址
00403FAD . FFD0 call eax----->调用MSVBVM60.DllFunctionCall,返回值放到eax中.
00403FAF .- FFE0 jmp eax---->eax指向kernel32.GetVolumeInformationA地址
00403F54 . 6B 65 72 6E 6>ascii "kernel32.dll",0
00403F61 00 db 00
00403F62 00 db 00
00403F63 00 db 00
00403F64 16 db 16
00403F65 00 db 00
00403F66 00 db 00
00403F67 00 db 00
00403F68 . 47 65 74 56 6>ascii "GetVolumeInformA"
给出SDK Ansi kernel32.GetVolumeInformationA函数原形
kernel32.GetVolumeInformationA(
string lpRootPathName,
string lpVolumeNameBuffer,
int nVolumeNameSize,
ref int lpVolumeSerialNumber,
int lpMaximumComponentLength,
int lpFileSystemFlags,
string lpFileSystemNameBuffer,
int nFileSystemNameSize
);
再看堆栈,:
0012FBEC 004103C6 --->GetVolumeInformationA的返回地址
0012FBF0 0014FAFC--->lpRootPathName
0012FBF4 001501C4--->lpVolumeNameBuffer
0012FBF8 000000FF--->nVolumeNameSize
0012FBFC 0012FC54---->lpVolumeSerialNumber
0012FC00 0012FC28---->lpMaximumComponentLength
0012FC04 0012FC24--->lpFileSystemFlags
0012FC08 0015009C--->lpFileSystemNameBuffer
0012FC0C 000000FF--->nFileSystemNameSize
看内存
00403F14 4D 6F 64 75 Modu
00403F24 6C 65 31 00 66 72 6D 4D 61 69 6E 00 66 72 6D 7A le1.frmMain.frmz
00403F34 68 75 63 65 00 00 00 00 66 72 6D 41 62 6F 75 74 huce....frmAbout
00403F44 00 00 00 00 66 6C 61 73 68 00 00 00 0D 00 00 00 ....flash.......
00403F54 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 00 kernel32.dll....
00403F64 16 00 00 00 47 65 74 56 6F 6C 75 6D 65 49 6E 66 ...GetVolumeInf
00403F74 6F 72 6D 61 74 69 6F 6E 41 00 00 00 ormationA...
kernel32.GetVolumeInformationA是在Module1.frmMain.frmzhuce单元声明的,总结一下:VB调用动态连接库中
API可以通过VB虚拟机内置MSVBVM60.DllFunctionCall(类似SDK API:LoadLibrary和GetProcAddrees)调用,至于之前
那些冗余的步骤都是把Unicode参数序列化成Ansi版,关键之处还是MSVBVM60.DllFunctionCall起作用.
一篇发不开,分两篇发。。。。
到这里注册用的本地机器码就是调用kernel32.GetVolumeInformationA得到C磁盘的卷标标识,只是VB调用一个SDK API圈圈多多而已. 好了继续.这个函数返回之后: 00410912 . A3 08E14300 mov [43E108],eax--->eax返回c:\磁盘的卷标给机器码全局变量[43E108] 00410917 . 8D4D DC lea ecx,[ebp-24] 0041091A . FF15 3C114000 call [<&MSVBVM60.__vbaFreeStr>] 00410920 . C745 FC 0C000>mov dword ptr [ebp-4],0C----->状态标志 00410927 . 833D 08E14300>cmp dword ptr [43E108],0--->比较机器码全局变量[43E108] 0041092E . 7D 13 jge short 00410943--->小于0就跳 00410930 . C745 FC 0D000>mov dword ptr [ebp-4],0D 00410937 . A1 08E14300 mov eax,[43E108] 0041093C . F7D8 neg eax 0041093E . A3 08E14300 mov [43E108],eax 00410943 > C745 FC 0F000>mov dword ptr [ebp-4],0F----->状态标志 0041094A . 8B0D 08E14300 mov ecx,[43E108] 00410950 . 81F1 AFFA2D01 xor ecx,12DFAAF-------------->机器码全局变量[43E108]与常数12DFAAF相互异或 00410956 . 390D 0CE14300 cmp [43E10C],ecx-------->[43E10C]关键全局变量存放正确的注册码 0041095C . 75 15 jnz short 00410973--------->关键部分 0041095E . C745 FC 10000>mov dword ptr [ebp-4],10 00410965 . 66:C705 14E04>mov word ptr [43E014],0FFFF----------->关键标志全局变量[43E014],0041096E . E9 DD000000 jmp 00410A50 分析次数计算,经过分析程序把天数保存在\wzj\4\number.txt中了,而读出的时候程序把天数保存在0043E110全局变量中当使用次数超过了3次,就提示出注册Nag来 ------------------------------------------------------------------------------------------------ 0041098A . 8B15 18E04300 mov edx,[43E018]----------->D:\Program Files\gzwlqj\ 00410990 . 52 push edx 00410991 . 68 30424000 push 00@R_403_448@230 ----->UNICODE "wzj\4\" 00410996 . FF15 34104000 call [<&MSVBVM60.__vbaStrCat>] 0041099C . 8BD0 mov edx,eax--------- 0041099E . 8D4D DC lea ecx,[ebp-24] 004109A1 . FF15 20114000 call [<&MSVBVM60.__vbaStrMove>] 004109A7 . 50 push eax 004109A8 . 68 E83F4000 push 00403FE8 ------------->UNICODE "number.txt" 004109AD . FF15 34104000 call [<&MSVBVM60.__vbaStrCat>] 004109B3 . 8BD0 mov edx,eax 004109B5 . 8D4D D8 lea ecx,[ebp-28] 004109B8 . FF15 20114000 call [<&MSVBVM60.__vbaStrMove>] 004109BE . 50 push eax-------->D:\Program Files\gzwlqj\wzj\4\number.txt 004109BF . 6A 01 push 1 004109C1 . 6A FF push -1 004109C3 . 6A 01 push 1 004109C5 . FF15 DC104000 call [<&MSVBVM60.__vbaFileOpen>] --->打开wzj\4\number.txt文件 004109CB . 8D45 D8 lea eax,[ebp-28] 004109CE . 50 push eax 004109CF . 8D4D DC lea ecx,[ebp-24] 004109D2 . 51 push ecx 004109D3 . 6A 02 push 2 004109D5 . FF15 F0104000 call [<&MSVBVM60.__vbaFreeStrList>]--->释放局部变量 004109DB . 83C4 0C add esp,0C 004109DE . C745 FC 14000>mov dword ptr [ebp-4],14 004109E5 . 68 10E14300 push 0043E110--------------->0043E110全局变量保存天数 004109EA . 6A 01 push 1---------->文件号 004109EC . 68 04@R_403_448@000 push 00@R_403_448@004 004109F1 . FF15 B8104000 call [<&MSVBVM60.__vbaInputFile>]-----> 004109F7 . 83C4 0C add esp,0C 004109FA . C745 FC 15000>mov dword ptr [ebp-4],15 00410A01 . 6A 01 push 1----->文件号 00410A03 . FF15 6C104000 call [<&MSVBVM60.__vbaFileClose>]---->关闭文件 00410A09 . C745 FC 16000>mov dword ptr [ebp-4],16 00410A10 . 66:833D 10E14>cmp word ptr [43E110],1 --->天数比较,是否等于1 00410A18 . 75 36 jnz short 00410A50--->关键部分:当等于1的时候好象改变\number.txt文件属性为隐藏 到这里又出现比较使用次数: 00410CAE . 66:833D 10E14>cmp word ptr [43E110],3---->当次数大于3的时候,00410CB6 0F8E 04010000 jle 00410DC0--->关键部分:次数大于3的时候,就跳出Nag,之后调用MSVBVM60.rtcShell启动官方网站提示用户注册 使用次数Nag分析完毕了,鼠标指点一二,就over了. ======================================================================================================================================== 之后再分析两个关键注册事件过程: 第一个是:点击"注册"菜单命令过程.如果没有注册或者是注册码不对,当点击"注册"菜单命令的时候它就跳出注册窗口来提示你注册. 如果你是注册用户,你点击"注册"菜单命令,它会提示你已经是是注册用户. 事件入口: 00417190 > \55 push ebp 00417191 . 8BEC mov ebp,esp 00417193 . 83EC 0C sub esp,0C 00417196 . 68 C6164000 push <jmp.&MSVBVM60.__vbaExceptHandler> 0041719B . 64:A1 0000000>mov eax,fs:[0] 004171A1 . 50 push eax 004171A2 . 64:8925 00000>mov fs:[0],esp-------->构造完毕SEH 004171A9 . 81EC 84000000 sub esp,84----------->分配局部变量 004171AF . 53 push ebx 004171B0 . 56 push esi 004171B1 . 57 push edi 004171B2 . 8965 F4 mov [ebp-C],esp 004171B5 . C745 F8 D8144>mov dword ptr [ebp-8],004014D8 004171BC . 8B45 08 mov eax,[ebp+8] 004171BF . 8BC8 mov ecx,eax 004171C1 . 83E1 01 and ecx,1 004171C4 . 894D FC mov [ebp-4],ecx 004171C7 . 24 FE and al,0FE 004171C9 . 50 push eax 004171CA . 8945 08 mov [ebp+8],eax 004171CD . 8B10 mov edx,[eax]------>eax是菜单组件对象地址,004171CF . FF52 04 call [edx+4] ---->MSVBVM60.Zombie_AddRef VB事件调用固定模式函数调用,引用虚拟机内的COM组件对象 004171D2 . 33FF xor edi,edi 004171D4 . 66:833D 14E04>cmp word ptr [43E014],0FFFF----->标志全局变量[43E014]在上边分析给出,0FFFF是注册成功的标志 004171DC . 897D E8 mov [ebp-18],edi 004171DF . 897D D8 mov [ebp-28],edi 004171E2 . 897D C8 mov [ebp-38],edi 004171E5 . 897D B8 mov [ebp-48],edi 004171E8 . 897D A8 mov [ebp-58],edi 004171EB . 897D 98 mov [ebp-68],edi 004171EE . 897D 88 mov [ebp-78],edi 004171F1 . 0F85 9A000000 jnz 00417291------>关键跳:不相等就跳出注册窗口提示注册 第一个事件过程分析完毕:鼠标指点一二,就over了. ------------------------------------------------------------------------------------------------------------ 第二是注册窗口的事件处理过程.当输入注册码,点击确认button然后进入注册算法中,如果输入超过三次就宣布game,over... 这里用到了几个浮点指令做比较,如果注册码正确就写入到隐藏文件config.txt中. 事件入口: 0043C4F0 > \55 push ebp 0043C4F1 . 8BEC mov ebp,esp 0043C4F3 . 83EC 0C sub esp,0C 0043C4F6 . 68 C6164000 push <jmp.&MSVBVM60.__vbaExceptHandler> 0043C4FB . 64:A1 0000000>mov eax,fs:[0] 0043C501 . 50 push eax 0043C502 . 64:8925 00000>mov fs:[0],esp 0043C509 . 81EC B0000000 sub esp,0B0 0043C533 . 8B15 08E14300 mov edx,[43E108] ---->全局变量[43E108]存放本地机器码 0043C539 . 33DB xor ebx,ebx 0043C53B . 81F2 AFFA2D01 xor edx,12DFAAF---->与12DFAAF异或保存在edx中. 0043C541 . 56 push esi 0043C542 . 8915 0CE14300 mov [43E10C],edx ---> [43EI0C]变量在上边出现一次,它正确的注册编码 0043C57E . 8D45 E8 lea eax,[ebp-18] --->[ebp-18]局部变量存取用户输入的注册码:qiweixue 0043C581 . 50 push eax 0043C582 . 57 push edi 0043C583 . 8B17 mov edx,[edi]--->Edit组件地址 0043C585 . FF92 A0000000 call [edx+A0] ---> 虚函数取Edit的用户输入内容 0043C58B . 3BC3 cmp eax,ebx----> 0043C58D . DBE2 fclex--->浮点指令清除异常 0043C58F . /7D 12 jge short 0043C5A3 0043C591 . |68 A0000000 push 0A0 0043C596 . |68 DC6E4000 push 00406EDC 0043C59B . |57 push edi 0043C59C . |50 push eax 0043C59D . |FF15 3C104000 call [<&MSVBVM60.__vbaHresultCheckObj>] ; MSVBVM60.__vbaHresultCheckObj 0043C5A3 > \8B4D E8 mov ecx,[ebp-18] ; 存取用户编码的输入:qiweixue 0043C5A6 . 51 push ecx 0043C5A7 . FF15 48114000 call [<&MSVBVM60.#581>] ; MSVBVM60.rtcR8ValFromBstr 0043C5AD . FF15 60104000 call [<&MSVBVM60.__vbaFpR8>] ; MSVBVM60.__vbaFpR8 0043C5B3 . DB05 0CE14300 fild dword ptr [43E10C]---> [43EI0C]压入浮点栈 0043C5B9 . DD9D 3CFFFFFF fstp qword ptr [ebp-C4]----->[ebp-C4]压入浮点栈 0043C5BF . DC9D 3CFFFFFF fcomp qword ptr [ebp-C4]---------->浮点比较 0043C5C5 . DFE0 fstsw ax------------>比较状态给ax 0043C5C7 . F6C4 40 test ah,40 0043C5CA . 74 07 je short 0043C5D3------------->不相等就over掉了. 0043C5CC . B8 01000000 mov eax,1--->正确标志true给eax 0043C5D1 . EB 02 jmp short 0043C5D5 0043C5D3 > 33C0 xor eax,eax--->错误标志false给eax 0043C5D5 > F7D8 neg eax 0043C5D7 . 8D4D E8 lea ecx,[ebp-18] ; 存取用户编码 0043C5DA . 66:8BF8 mov di,ax 0043C5DD . FF15 3C114000 call [<&MSVBVM60.__vbaFreeStr>] --->析构字符串 0043C5E3 . 8D4D E0 lea ecx,[ebp-20] 0043C5E6 . FF15 40114000 call [<&MSVBVM60.__vbaFreeObj>] ---> 析构对象 0043C5EC . 66:3BFB cmp di,bx 0043C5EF . 0F84 86010000 je 0043C77B---->关键:如果相等就over了,然后在比较是否是第三次输入.如果不相等就注册正确,把注册码输入到config.txt中. 以上全部分析完毕,注册算法很简单,但是跟踪起来却相当不轻松. 第一调用VB约定太杂乱,没有统一性.第二调用本地SDK API,需要Unicode转化Ansi也相当烦琐.第三用到浮点指令判断.第四用户程序堆栈与虚拟机相互通讯传地址,经常eax寄存器out出来com组件地址引用,一堆一堆接口指针却大多没有sig. 错误之处,多谢指教. 注册机C#源代码: ======================================================== using System; using System.Text; using System.Collections.Generic; using System.Runtime.InteropServices; namespace Pediy { class Pediy { [DllImport("kernel32.dll")] private static extern int GetVolumeInformation( string lpRootPathName,string lpVolumeNameBuffer,int nVolumeNameSize,ref int lpVolumeSerialNumber,int lpMaximumComponentLength,int lpFileSystemFlags,string lpFileSystemNameBuffer,int nFileSystemNameSize ); public static int GetRootVolume(string RootID) { const int MAX_FILENAME_LEN = 256; int retVal = 0; int a = 0; int b = 0; string str1 = null; string str2 = null; int i = GetVolumeInformation( RootID,str1,MAX_FILENAME_LEN,ref retVal,a,b,str2,MAX_FILENAME_LEN ); return retVal; } static void Main(string[] args) { int key; Pediy prg = new Pediy(); key = Pediy.GetRootVolume(@"c:\"); if(key>0) { System.Console.WriteLine(@"LocalKey:"+key); key=key ^ 0x12DFAAF; System.Console.WriteLine(@"RegisterKey:" +key); } else { key=((~key)+0x1); System.Console.WriteLine(@"LocalKey:"+key); key=((~key)+0x1)^0x12DFAAF; System.Console.WriteLine(@"RegisterKey:" +key) } System.Console.ReadLine(); } } } .NET sdk 2.0