欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

休闲麻将 P-CODE 浅析

休闲麻将 P-CODE 浅析

【文章作者】GoOdLeiSuRe
【分析时间】2007年3月30日
【分析说明】本人很菜,完全入门水准,恳请指正,谢谢。
【破解过程】
主程序:Mj.exe
PEiD检查:ASPack 2.12 -> Alexey Solodovnikov
脱壳:用AspackDie直接脱
PEiD再检查:Microsoft Visual Basic 5.0 / 6.0
编译方式:用OllyDBG加载,感觉是P-CODE,用WKTVBDebugger加载,果然是P-CODE

代码:
//加载后停于此

0049A850: 00 LargeBos

//一路F8瞧瞧

0049A852: 00 LargeBos

0049A854: 4B OnErrorGoto Next

0049A857: 00 LargeBos

0049A859: 04 FLdRfVar 0070FB56h

0049A85C: 04 FLdRfVar 0070FB58h

0049A85F: 05 ImpAdLdRf

0049A862: 24 NewIfNullPr 0041CEA8

0049A865: 0D VCallHresult CVBApp::get_App

0049A86A: 08 FLdPr

0049A86D: 0D VCallHresult get__ipropPrevInstanceAPP

0049A872: 6B FLdI2

0049A875: 1A FFree1Ad

0049A878: 1C BranchF 0049A87F (Jump )

0049A87B: 00 LargeBos

0049A87D: FC Lead1/End

0049A87F: 00 LargeBos

//读取安装目录吧?

0049A881: 1B LitStr: 'SetupDir'

0049A884: 43 FStStrCopy

0049A87B: 00 LargeBos

0049A87D: FC Lead1/End

0049A87F: 00 LargeBos

0049A881: 1B LitStr: 'SetupDir'

0049A884: 43 FStStrCopy

0049A887: 04 FLdRfVar 0070FB48h

//注册表字符串,说不定用户名与注册码也会储存在这儿

0049A88A: 1B LitStr: 'SoftWare\NetMJ\Infomation'

0049A88D: 43 FStStrCopy

0049A890: 04 FLdRfVar 0070FB4Ch

0049A893: F5 LitI4: -> 80000002h -2147483646

0049A898: 59 PopTmpLdAdStr

//读取注册表“SoftWare\NetMJ\Infomation”,获取“SetupDir”值

0049A89B: 0B ImpAdCallI2 modPubTools!0044C5C4h

0049A8A0: 31 FStStr

……

//F5运行


在窗口下拉列表中看到了重要窗口:frmUserReg

在弹出窗口选择:cmdOK

接着返回主程序,输入一些注册信息,一但“确定”就会中断:
代码:
0044485C: 04 FLdRfVar 0070F378h

0044485F: 21 FLdPrThis 004FC52Ch

00444860: 0F VCallAd frmUserReg.txtUserName

00444863: 19 FStAdFunc 0070F37C

00444866: 08 FLdPr

00444869: 0D VCallHresult get__ipropTEXTEDIT

0044486E: 6C ILdRf 00000000h

00444871: 0B ImpAdCallI2 rtcTrimBstr on address 660E6AC5h

//用户名

00444876: FD Lead2/PopTmpLdAdStr

0044487A: 1B LitStr: 'RegName'

0044487D: 43 FStStrCopy

00444880: 04 FLdRfVar 0070F36Ch

00444883: 1B LitStr: 'SoftWare\NetMJ\Infomation'

00444886: 43 FStStrCopy

00444889: 04 FLdRfVar 0070F370h

0044488C: F5 LitI4: -> 80000002h -2147483646

00444891: 59 PopTmpLdAdStr

00444894: 0A ImpAdCallFPR4 modPubTools!0044507Ch

00444899: 32 FFreeStr

004448A4: 1A FFree1Ad

004448A7: 04 FLdRfVar 0070F378h

004448AA: 21 FLdPrThis 004FC52Ch

004448AB: 0F VCallAd frmUserReg.txtPassword

004448AE: 19 FStAdFunc

004448B1: 08 FLdPr

004448B4: 0D VCallHresult get__ipropTEXTEDIT

004448B9: 6C ILdRf 00000000h

004448BC: 0B ImpAdCallI2 rtcTrimBstr on address 660E6AC5h

//注册码

004448C1: FD Lead2/PopTmpLdAdStr

004448C5: 1B LitStr: 'RegCode'

004448C8: 43 FStStrCopy

004448CB: 04 FLdRfVar 0070F36Ch

004448CE: 1B LitStr: 'SoftWare\NetMJ\Infomation'

004448D1: 43 FStStrCopy

004448D4: 04 FLdRfVar 0070F370h

004448D7: F5 LitI4: -> 80000002h -2147483646

004448DC: 59 PopTmpLdAdStr

004448DF: 0A ImpAdCallFPR4 modPubTools!0044507Ch

004448E4: 32 FFreeStr

很明显,注册信息存储于注册表项:SoftWare\NetMJ\Infomation
RegName 用户名
RegCode 注册码
F5,主程序要求退出
重新加载,并由以上信息“ImpAdCallI2 modPubTools!0044C5C4h”找出调用注册信息的位置
代码:
//用户名 在此使用:GoOdLeiSuRe

00449928: 23 FStStrNoPop -> 'GoOdLeiSuRe'

0044992B: 0B ImpAdCallI2 rtcLowerCaseBstr on address 660E6A2Dh

00449930: 31 FStStr -> 'goodleisure'

00449933: 32 FFreeStr

0044993C: 1B LitStr: 'regcode'

0044993F: 43 FStStrCopy

00449942: 04 FLdRfVar 0070F690h

00449945: 1B LitStr: 'SoftWare\NetMJ\Infomation'

00449948: 43 FStStrCopy

0044994B: 04 FLdRfVar 0070F694h

0044994E: F5 LitI4: -> 80000002h -2147483646

00449953: 59 PopTmpLdAdStr

00449956: 0B ImpAdCallI2 modPubTools!0044C5C4h

//注册码 在此使用:7878787878

0044995B: 31 FStStr -> '7878787878'

0044995E: 32 FFreeStr

00449965: 05 ImpAdLdRf

00449968: F4 LitI2_Byte: -> 1h 1

0044996A: FC Lead1/FnUBound

0044996C: F5 LitI4: -> 1h 1

00449971: AA AddI4

00449972: 71 FStR4

00449975: 6C ILdRf 004F08F8h

//用户名长度

00449978: 4A FnLenStr 004F08F4h , 11 chars

00449979: F5 LitI4: -> 1h 1

0044997E: DB GtI4

0044997F: 6C ILdRf 004F0E44h

//注册码长度

00449982: 4A FnLenStr 004F0E40h , 10 chars

00449983: F5 LitI4: -> Ah 10

//比较

00449988: C7 EqI4

00449989: C4 AndI4

0044998A: 1C BranchF 00449A03

0044998D: 6C ILdRf 004F0E44h

//反置注册码 StrReverse()

00449990: 0B ImpAdCallI2 rtcStrReverse on address 660F7DF1h

00449995: 31 FStStr 004F1590h to 0070F7A4h -> '8787878787'

00449998: F5 LitI4: -> 0h 0

0044999D: 04 FLdRfVar 0070F69Ch

004499A0: 05 ImpAdLdRf

004499A3: F4 LitI2_Byte: -> 1h 1

004499A5: FC Lead1/FnUBound

004499A7: FE Lead3/ForI4:

004499AD: 6C ILdRf 00000003h

004499B0: 05 ImpAdLdRf

004499B3: 9E Ary1LdI4

//注册码长度

004499B4: 4A FnLenStr 004E5594h , 10 chars

004499B5: F5 LitI4: -> Ah 10

//比较

004499BA: C7 EqI4

004499BB: 1C BranchF 004499FB 

004499BE: 1B LitStr: '听'

//取其7位长度

004499C1: F5 LitI4: -> 7h 7

004499C6: 6C ILdRf 00000000h

004499C9: 05 ImpAdLdRf

004499CC: 9E Ary1LdI4

004499CD: 0B ImpAdCallI2 rtcRightCharBstr on address 660E6362h

004499D2: 23 FStStrNoPop

 -> '8888889'

 -> '3925743'

004499D5: 2A ConcatStr

004499D6: 31 FStStr

 -> 'zjm8888889'

 -> 'zjm3925743'

004499D9: 2F FFree1Str 004F82B0h

004499DC: 6C ILdRf 004F1590h

004499DF: 04 FLdRfVar 0070F694h

004499E2: 04 FLdRfVar 0070F6A8h

004499E5: 04 FLdRfVar 0070F6A0h

//关键处

004499E8: 10 ThisVCallHresult 0043EF68->0043EF68

004499ED: 6C ILdRf 00000000h

//字符串比较

004499F0: 30 EqStr

004499F2: 2F FFree1Str

004499F5: 1C BranchF 004499FB (Jump ?

004499F8: 1E Branch 00449A03

004499FB: 04 FLdRfVar 0070F69Ch

//循环一次

004499FE: 66 NextI4: jump to 004499AD

00449A03: 6C ILdRf 00000000h

00449A06: 05 ImpAdLdRf

00449A09: F4 LitI2_Byte: -> 1h 1

00449A0B: FC Lead1/FnUBound

00449A0D: D6 LeI4

00449A0E: 1C BranchF 00449A50

00449A11: F4 LitI2_Byte: -> 0h 0

00449A13: 21 FLdPrThis 004E5EF8h

00449A14: 0F VCallAd frmGameMain.mnuReg

00449A17: 19 FStAdFunc

00449A1A: 08 FLdPr

00449A1D: 0D VCallHresult put__ipropVISIBLEMENU

关键处
代码:
0043EE68: FF Lead4/ZeroRetVal

0043EE6A: 80 ILdI4

//用户名长度

0043EE6D: 4A FnLenStr

0043EE6E: F5 LitI4: -> 7h 7

0043EE73: DB GtI4

//10>7?

0043EE74: 1C BranchF 0043EE8A

0043EE77: F5 LitI4: -> 7h 7

0043EE7C: 80 ILdI4

//取右边7位:goodleisure

0043EE7F: 0B ImpAdCallI2 rtcRightCharBstr on address 660E6362h

0043EE84: 31 FStStr -> 'leisure'

0043EE87: 1E Branch 0043EE9

0043EE8A: 80 ILdI4

0043EE8D: 43 FStStrCopy

0043EE90: F5 LitI4: -> 1h 1

0043EE95: 6C ILdRf 00000000h

//取左边1位:leisure

0043EE98: 0B ImpAdCallI2 rtcLeftCharBstr on address 660E625Eh

0043EE9D: 31 FStStr -> 'l'

0043EEA0: F5 LitI4: -> 0h 0

0043EEA5: F5 LitI4: -> FFFFFFFFh -1

0043EEAA: F5 LitI4: -> 1h 1

0043EEAF: F5 LitI4: -> 0h 0

0043EEB4: 6C ILdRf 004E2EBCh

0043EEB7: 6C ILdRf 004F0E44h

//去除字符“l”:leisure

0043EEBA: 0B ImpAdCallI2 rtcReplace on address 660F7E44h

0043EEBF: 31 FStStr 004F2CA4h to 0070F6C4h -> eisure

0043EEC2: 6C ILdRf 004E2EBCh

0043EEC5: F5 LitI4: -> 0h 0

//比较字符串,是否为空?

//以前版本存在同字符漏洞。

0043EECA: 30 EqStr

0043EECC: 1C BranchF 0043EED5

0043EECF: FF Lead4/ExitProcCbHresult

0043EED5: 80 ILdI4

//zjm8888889

0043EED8: 6C ILdRf 004F0E44h

0043EEDB: 2A ConcatStr

0043EEDC: 31 FStStr 004E5EB4h to 0070F6C4h -> zjm8888889leisure

0043EEDF: F5 LitI4: -> 0h 0

0043EEE4: 43 FStStrCopy

0043EEE7: F5 LitI4: -> 1h 1

0043EEEC: 04 FLdRfVar 0070F5C8h

0043EEEF: 6C ILdRf 004F2CA4h

0043EEF2: 4A FnLenStr -> 17 char

//FOR 循环,字符串长

0043EEF3: FE Lead3/ForI4:

0043EEF9: 6C ILdRf 00000000h

0043EEFC: 28 LitVarI2 1h , 1

0043EF01: 6C ILdRf 00000001h

//zjm8888889leisure

0043EF04: 6C ILdRf 004E5EB4h

0043EF07: 0B ImpAdCallI2 rtcMidCharBstr on address 660E64A6h

0043EF0C: 23 FStStrNoPop -> 逐个字符(z,j,m,...)

//各字符ASC()码

0043EF0F: 0B ImpAdCallI2 rtcAnsiValueBstr on address 660E657Bh

0043EF14: E7 CI4UI1

//与上一循环而得的商值相加

0043EF15: AA AddI4

//ABS()

0043EF16: BC FnAbsI4

//STR()

0043EF17: 71 FStR4

0043EF1A: 2F FFree1Str

0043EF1D: 35 FFree1Var

0043EF20: 6C ILdRf 00000000h

//上述求得的值

0043EF23: 6C ILdRf 0000007Ah

0043EF26: F5 LitI4: -> Ah 10

//与10求余

0043EF2B: C2 ModI4

//STR()

0043EF2C: FE CStrI4

0043EF2E: 23 FStStrNoPop -> 余值字符串

0043EF31: 2A ConcatStr

0043EF32: 31 FStStr

0043EF35: 2F FFree1Str

0043EF38: 6C ILdRf 0000007Ah

0043EF3B: F5 LitI4: -> Ah 10

//与10相除的商

0043EF40: C0 IDvI4

//STR()

0043EF41: 71 FStR4

0043EF44: 04 FLdRfVar 0070F5C8h

//Next 循环

0043EF47: 66 NextI4: jump to 0043EEF9

0043EF4C: F5 LitI4: -> Ah 10

0043EF51: 6C ILdRf 004F2CFCh

//取右边10位长:2234266963 -> 实际上反置过来就是需要的注册码了

0043EF54: 0B ImpAdCallI2 rtcRightCharBstr on address 660E6362h

0043EF59: 31 FStStr

0043EF5C: 6C ILdRf 004F2CFCh

【算法分析】 
1,用户名长度要大于2位,转化为小写; 
2,注册码长度为10位;
3,zjm + 机器码右7位 + 用户名右7位
4,逐个取字符,求ASCII码,与10除,余数转化为字符,商值与下一字符的ASCII码相加
5,余数字符串反置即为注册码
【网络验证】
软件在连网的状态下,会进行验证(用Iris捕获):
HTTP://zj1.51.net/cgi%2Dbin/mjlink.cgi?work=update&rgn=用户名&hid=XXXXXXX&mid=机器码右7位&mid0=YYYYYYY&mid1=&ver=312
返回ckerror则清除注册表内的注册码,返回ckok则验证正确
缺少用户名等信息不全,会返回一些升级信息
具体分析代码就省略了。
(参考)避开网络通验证,通常可修改hosts文件(位于WINDOWS\system32\drivers\etc),添加:
127.0.0.1    zj1.51.net

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功