好友
阅读权限30
听众
最后登录1970-1-1
|
本帖最后由 L4Nce 于 2014-11-3 02:03 编辑
珍惜生命,远离海风!!!
海风前辈的cm,简直无情。还要自带vm,分析过去绝对能把人弄死。不带这样玩的吧,不带这样玩的吧!!
废话说多了就不好了,估计大家都想看一下这个cm的分析。咳咳,就让我慢慢说明。
大牛的想法我不懂,大牛的世界我更加不懂。不过从中抽取一点有用的信息出来,也是可以的。
首先,还是得有一个虚拟机的思想。这个程序有两段是加了VM的,虽然架构与我们熟知的不太一样就是了。
首先看一下main主体
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | 00401089 |. C785 0CF5FFFF C2C7F> MOV [ LOCAL .701], 0x97F6C7C2
00401093 |. 898D 04F5FFFF MOV [ LOCAL .703], ECX
-------------------> 循环 <------------------------------> 循环 <----------------------------------------------
00401099 >|> 8B85 0CF5FFFF / MOV EAX , [ LOCAL .701]
0040109F |. 89C1 | MOV ECX , EAX
004010A1 |. 81E9 005CC17F | SUB ECX , 0x7FC15C00
004010A7 |. 8985 00F5FFFF | MOV [ LOCAL .704], EAX
...
0041397A >|> \8B85 00F5FFFF | MOV EAX , [ LOCAL .704]
00413980 |. 2D C2C7F697 | SUB EAX , 0x97F6C7C2
00413985 |. 8985 94CAFFFF | MOV [ LOCAL .3419], EAX
0041398B |. 0F84 E2F70000 | JE <CrackMe.loc_423173>
...
00423173 >|> \B8 11A51829 | MOV EAX , 0x2918A511
00423178 |. B9 3D774A50 | MOV ECX , 0x504A773D
...
004231CF |. 0F45F1 | CMOVNE ESI , ECX
004231D2 |. 89B5 0CF5FFFF | MOV [ LOCAL .701], ESI
004231D8 |. E9 3B7F0400 | JMP <CrackMe.loc_46B118>
...
0046B118 >\>^\E9 7C5FF9FF \ JMP <CrackMe.loc_401099>
|
就是这样,完成了一次vEip的处理后,根据处理结果更新vEip,接着又进行下一个处理,这样来完成程序的功能。
并且,这里每一个vEip的处理函数里面都有两个跳转常数,并且根据运算结果进行选择,所以硬要弄下去的话可以弄出非常多的vEip分支的。哈哈,简直得跪。
还有另外一段完成Name与Pass校验的代码也是类似的,应该很容易就能看出来。
我分析了一下,发现这段vm是用于处理数据输入的,真正的验证还在另外一段VM中:0046B120
于是,我们就去分析vm吧。。。也不太现实。能不能降低一下工作量呢?可以的。
现在我们已经知道了有vEip,以及跳转常数,以及他们之间的关系,那么自然就可以通过跳转常数计算出跳转地址,有了这些,就能基本上弄清楚程序的流程了,所以,这里我写了一段脚本来解析验证函数段的跳转地址:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | //该脚本用于52CM大赛海风月影前辈CM解析。
// By F8LEFT 2014.11.1
LOG ""
LOG "该脚本由F8LEFT制作,用于解析第四届52CM大赛中海风前辈的CM"
LOG "不确定会有什么bug,咳咳,真蛋疼"
VAR CStart //解析开始地址
VAR CEnd //解析结束地址
jmp Omain
CheckProc: //验证段主体
VAR Ceip //更新的当前地址
MOV Ceip, CStart
VAR Temp
VAR Tempeip //中间变量
VAR TempAddr //中间变量
VAR ConstEAX //常数1
VAR ConstEDX //常数2
VAR JmpAddr1
VAR JmpAddr2
VAR Strbuf
VAR AddrChara
MOV AddrChara, #B8????????B9# // mov eax , DWORD , mov edx , DWORD
VAR ConstChara
MainLoop:
FIND Ceip, AddrChara
MOV Ceip, $RESULT
CMP Ceip, 0
JE MainEnd //退出地址
MOV Tempeip, Ceip
ADD Tempeip, 1 //定位到常数中
MOV ConstEAX, [Tempeip] //取常数1
ADD Tempeip, 5
MOV ConstEDX, [Tempeip] //取常数2
MOV TempAddr, CStart
FindLoop:
FIND TempAddr, ConstEAX
MOV TempAddr, $RESULT
SUB TempAddr, 1
// CMP [TempAddr], #2D#,1
ADD TempAddr, 0D
MOV Temp, [TempAddr]
ADD Temp, TempAddr
ADD Temp, 4
MOV JmpAddr1, Temp
MOV TempAddr, CStart
FIND TempAddr, ConstEDX
MOV TempAddr, $RESULT
SUB TempAddr, 1
// CMP [TempAddr], #2D#,1
ADD TempAddr, 0D
MOV Temp, [TempAddr]
ADD Temp, TempAddr
ADD Temp, 4
MOV JmpAddr2, Temp
//Log out
MOV Tempeip, Ceip
EVAL "jmp {JmpAddr1}"
CMT Tempeip, $RESULT
ADD Tempeip,5
EVAL "jmp {JmpAddr2}"
CMT Tempeip, $RESULT
EVAL "{Ceip} : jmp {JmpAddr1} jmp {JmpAddr2}"
MOV Strbuf, $RESULT
LOG Strbuf
WRTA "Analyse.txt" , Strbuf
MOV Ceip, Tempeip
JMP MainLoop
MainEnd:
ret
Omain:
MOV CStart, 46B120
MOV CEnd, 49156F
CALL CheckProc
ret
|
输出的结果大致如下,(部分),有部分地址没有解析出来,不过不影响阅读
[Asm] 纯文本查看 复制代码 1 2 3 4 5 6 7 8 | 477025 : jmp 48E1F4 jmp 477054
477054 : jmp 48E1F4 jmp 477127
477136 : jmp 48E203 jmp 4771DF
4771DF : jmp 48E203 jmp 4772EC
4772FB : jmp 48E212 jmp 47739D
47739D : jmp 48E212 jmp 47748A
477499 : jmp 48E221 jmp 477544
477544 : jmp 48E221 jmp 477634
|
这里我只复制了一部分,不过也能看出一点规律。首先,两个跳转地址相差都非常大。实际上 48E000以后的跳转都是用来退出vm的,而之前的vm则是代表这vm正常进行。
并且,最为重要的是,你将会看到,除了部分以外,这里的跳转都是跳向下一个地址的,所以大致上程序是顺序执行的。所以每当你看到它跳向vm分配的地方时,就可以直接在下一个地点F4了。
而那些特殊的跳转地址,如:
479231 : jmp 4793F2 jmp 479252
则需要得到关注了,因为这些是属于条件跳转,程序流程产生分支都是从这里开始的。而我爆破的地方都是从这种地方选的。
准备工作结束了,下面就是无脑的跟踪了。虽说如此,但是不实际上跟踪一下的话是不会懂的。咳咳,我下面直接贴出修改的地方:
验证
004856C4 . 8A96 173C0000 MOV DL, BYTE PTR DS:[ESI+0x3C17] ; --> SetTo0
00485A1C . 8A96 273C0000 MOV DL, BYTE PTR DS:[ESI+0x3C27] ; SetTo0
004863EA . 8A96 2E3C0000 MOV DL, BYTE PTR DS:[ESI+0x3C2E] ; set 0
00489ED0 . 8A96 123D0000 MOV DL, BYTE PTR DS:[ESI+0x3D12] ; set0
0048CFE6 . 8A96 533D0000 MOV DL, BYTE PTR DS:[ESI+0x3D53] ; Set1
Pass长度:
00479164 . 813F 30000000 CMP DWORD PTR DS:[EDI], 0x30 ; 比较长度
0047916A . 0F95C6 SETNE DH -> xor dh,dh
这里都改一改,就成功了,名字长度为[3~32],Pass长度在48以内就可以了。附上成功的图
|
|