新人破解eXeScope笔记
程序员文章站
2022-07-04 23:54:07
此文目的:
1、自我纪念一下,身为菜鸟的我在无任何参考下的破解处女作;
2、写完之后,发现破解这个程序的分析文章已经“烂大街”了,但是我还是希望能给目前跟我一样菜的...
此文目的:
1、自我纪念一下,身为菜鸟的我在无任何参考下的破解处女作;
2、写完之后,发现破解这个程序的分析文章已经“烂大街”了,但是我还是希望能给目前跟我一样菜的人,有所帮助,因为这里面包含了一些分析过程(心理描写),不像高手或者教材写的那样,基本上都是一下就直指问题核心,在我看来都是没有任何理由似的神来之笔,让我有些迷茫:高手是神,不是人;亲,那身为人的我该怎么办,这不是没法混了嘛?当然我明白这些不关键的理由在高手眼里也许不重要,同时写出来显得非常繁琐,但是对于目前身为菜鸟的我,我觉着这样写出来比较重要,这样不但能让我从细节中能学到更多的东西,同时让我知道高手应该是人,不是神,身为菜鸟的我还有希望赶上;所以我很繁琐的写出来,希望能帮助那些跟我有相同疑惑的同学;
PS:写出的内容基本上包含了我整个破解的过程及想法,很繁琐,有兴趣的可以当小说看看,一笑置之!如果各位觉着文中言语有冒犯之处,请多多谅解!
破解缘由:
这段时间在学习《加密与解密》第13章脱壳技术的时候,碰到2件事:
1、以前电脑上装了一个“文件夹加密”软件,但是有使用限制,所以很早就想实战破解一下;但是发现此软件是加壳处理过的,而当时我又完全不会手工脱壳,就想留着以后给自己实践用;恰巧这几天学到一点脱壳技术,就想实战一下,Y的失败了,信心大受打击;心想着后面还有好几章讲软件保护的,可能看完之后再去脱壳好点,故自我安慰后暂时放下了;
2、在练习PE文件优化操作时,打算用eXeScope(版本6.50)工具看看优化后的脱壳程序资源能不能被正常编辑,谁知二次操作后出现如下提示:
感觉有点倒霉,不过心中也有种喜悦之情在弥漫,因为又找到理由以及合适的软件去练下手了(目前个人时间安排比较紧,所以我认为去破解其它仅仅是为了练手目的而准备的软件来说,这种对我来说更有实用价值而已,勿怪);
破解过程:
首先用PEID看看该软件有没有加过壳(见下图),发现运气好,这个软件没加壳,所以心理负担少了一点,但是发现该软件是通过Delphi写的,又有点蛋疼起来了(因为本人Delphi没接触过),不过仔细想想破解跟语言关系应该不大,并且假设你只破解熟悉的语言写的程序,那还搞个屁呀,所以继续;
首先经过简单查找之后,发现注册功能是帮助菜单的菜单项,点击随便试用后,结果如下:
在输入错误的名字(111)跟ID(222)后,出现了“无效的ID或名字”这样一个字符串;
然后用Ollydbg加载eXeScope程序,并查找“无效的ID或名字”,神奇的是查找失败了(原因下文会提及);我勒个去,然后再查找“你的名字”等其他比较接近的字符串,也均以失败告终,当时就有点蒙了;随后又试了对CreateWindow,TranslateMessage,以及消息断点等等我能想到的方法去尝试,的确断点进来了,但是来到用户代码模块后,依然很迷茫;因为都ret了好几次,还是没找到处理注册逻辑的代码块;想想不会这么倒霉吧,第二次练手又失败,这打击没法接受呀!
已近中午,就跑去吃饭,期间仔细想了想,确定了几件事:
1、这一次破解必须要成功,因为连续失败影响太大;
2、没有出现的字符串可能包含在资源文件中,可以试着以资源方式打开此文件看看;随后吃完饭后就这么做了,见下图:
果然这个东西包含在一个字符串名为“TFReg”的对象中;Ok,感觉出现了部分曙光,随后就查找“TFReg”这个字符串,还好这个找到了,然后对这个数据地址下硬件断点;断过去之后,发现来到的地方离我预期的地方差的还是很远,至少向上返回好几层之后,都没找到;
没办法,在“必须搞定”的这种压力下,目前只能一步一步跟踪,基本上每次call都进去瞄了眼,不断的重复试验;皇天不负有心人,2个多小时候后,终于被我*运的找到关键代码处(因为看到自己输入的字符串,同时还出现了“无效的ID或名称”),接下来就比较顺水了;至此得出的结论是一定要给自己压力;
破解之后,当时就觉着奇怪,为什么我搜索“无效的ID或名称”找不到,然后自己就人工去查找这个字符串,竟然被找到了,暗想难道是Ollydbg自带的查找功能有bug;多次试验后,才悲剧的发现“ID”前后存在空格;此处又得到一个经验:虽然打字不费力,但是以后查找字符串时,还是别打全了,O__O”…;
接下来就试着按常规思路去破解(查找关键字符串方式),也就是下面写的具体破解内容,随后常规方式也搞定了;这时想把第一次误打误撞方式破解找到代码关键点的过程再试验总结下,看能不能得出什么经验教训,不料此时却重复不出来了,原因应该是那种方式本来就不靠谱,同时已经通过常规查找成功,导致没有精力再来一遍;
以下是采用常规模式算出序列号(ID)的具体过程:
用Ollydbg加载eXeScope程序并按F9运行,随后按Ctrl+G输入跳转地址跳转到用户代码模块处,然后采用“超级字符串参考插件”查找相关字符串,见下图:
因为找出来的字符串比较多,所以直接搜索下“无效的”这几个字,找到我们希望的字符串,见下图:(如果用“无效的ID ”查找,千万别漏掉ID二个字符二边的空格,不然就找不到了)
双击找到的字符串,跳转到所引用的代码处,具体地址为004C2B5E,相关代码如下:
004C2A55 |. 55 PUSH EBP
004C2A56 |. 68 A12B4C00 PUSH eXeScope.004C2BA1
004C2A5B |. 64:FF30 PUSH DWORD PTR FS:[EAX]
004C2A5E |. 64:8920 MOV DWORD PTR FS:[EAX], ESP
004C2A61 |. A1 5CFC4C00 MOV EAX, DWORD PTR DS:[4CFC5C]
004C2A66 |. 8038 00 CMP BYTE PTR DS:[EAX], 0
004C2A69 |. 74 0F JE SHORT eXeScope.004C2A7A
004C2A6B |. C783 4C020000 02000000 MOV DWORD PTR DS:[EBX+24C], 2
004C2A75 |. E9 FF000000 JMP eXeScope.004C2B79
004C2A7A |> 8D55 FC LEA EDX, [LOCAL.1]
004C2A7D |. 8B83 F8020000 MOV EAX, DWORD PTR DS:[EBX+2F8]
004C2A83 |. E8 F4F8FAFF CALL eXeScope.0047237C
004C2A88 |. 8B55 FC MOV EDX, [LOCAL.1]
004C2A8B |. A1 E8FE4C00 MOV EAX, DWORD PTR DS:[4CFEE8]
004C2A90 |. E8 4F1FF4FF CALL eXeScope.004049E4
004C2A95 |. 8D55 F8 LEA EDX, [LOCAL.2]
004C2A98 |. 8B83 FC020000 MOV EAX, DWORD PTR DS:[EBX+2FC]
004C2A9E |. E8 D9F8FAFF CALL eXeScope.0047237C
004C2AA3 |. 8B55 F8 MOV EDX, [LOCAL.2] ; kernel32.7C817080
004C2AA6 |. A1 4CFE4C00 MOV EAX, DWORD PTR DS:[4CFE4C]
004C2AAB |. E8 341FF4FF CALL eXeScope.004049E4
004C2AB0 |. 8B15 4CFE4C00 MOV EDX, DWORD PTR DS:[4CFE4C] ; eXeScope.004D2E58
004C2AB6 |. 8B12 MOV EDX, DWORD PTR DS:[EDX]
004C2AB8 |. A1 54FC4C00 MOV EAX, DWORD PTR DS:[4CFC54]
004C2ABD |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2ABF |. E8 B8940000 CALL eXeScope.004CBF7C
004C2AC4 |. 84C0 TEST AL, AL
004C2AC6 |. 0F84 8D000000 JE eXeScope.004C2B59
004C2ACC |. A1 E8FE4C00 MOV EAX, DWORD PTR DS:[4CFEE8]
004C2AD1 |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2AD3 |. E8 7821F4FF CALL eXeScope.00404C50
004C2AD8 |. 85C0 TEST EAX, EAX
004C2ADA |. 7E 7D JLE SHORT eXeScope.004C2B59
004C2ADC |. 8D55 F0 LEA EDX, [LOCAL.4]
004C2ADF |. A1 FCFE4C00 MOV EAX, DWORD PTR DS:[4CFEFC]
004C2AE4 |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2AE6 |. E8 11FCFCFF CALL eXeScope.004926FC
004C2AEB |. 8B45 F0 MOV EAX, [LOCAL.4]
004C2AEE |. 8D4D F4 LEA ECX, [LOCAL.3]
004C2AF1 |. BA B82B4C00 MOV EDX, eXeScope.004C2BB8 ; .ini
004C2AF6 |. E8 2570F4FF CALL eXeScope.00409B20
004C2AFB |. 8B4D F4 MOV ECX, [LOCAL.3] ; kernel32._except_handler3
004C2AFE |. B2 01 MOV DL, 1
004C2B00 |. A1 2CBE4300 MOV EAX, DWORD PTR DS:[43BE2C]
004C2B05 |. E8 D293F7FF CALL eXeScope.0043BEDC
004C2B0A |. 8BF0 MOV ESI, EAX
004C2B0C |. A1 E8FE4C00 MOV EAX, DWORD PTR DS:[4CFEE8]
004C2B11 |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2B13 |. 50 PUSH EAX
004C2B14 |. B9 C82B4C00 MOV ECX, eXeScope.004C2BC8 ; name
004C2B19 |. BA D82B4C00 MOV EDX, eXeScope.004C2BD8 ; reg
004C2B1E |. 8BC6 MOV EAX, ESI
004C2B20 |. 8B38 MOV EDI, DWORD PTR DS:[EAX]
004C2B22 |. FF57 04 CALL NEAR DWORD PTR DS:[EDI+4] ; ntdll.7C96F7E7
004C2B25 |. A1 4CFE4C00 MOV EAX, DWORD PTR DS:[4CFE4C]
004C2B2A |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2B2C |. 50 PUSH EAX
004C2B2D |. BA D82B4C00 MOV EDX, eXeScope.004C2BD8 ; reg
004C2B32 |. B9 E42B4C00 MOV ECX, eXeScope.004C2BE4 ; id
004C2B37 |. 8BC6 MOV EAX, ESI
004C2B39 |. 8B38 MOV EDI, DWORD PTR DS:[EAX]
004C2B3B |. FF57 04 CALL NEAR DWORD PTR DS:[EDI+4] ; ntdll.7C96F7E7
004C2B3E |. 8BC6 MOV EAX, ESI
004C2B40 |. E8 9B10F4FF CALL eXeScope.00403BE0
004C2B45 |. A1 5CFC4C00 MOV EAX, DWORD PTR DS:[4CFC5C]
004C2B4A |. C600 01 MOV BYTE PTR DS:[EAX], 1
004C2B4D |. C783 4C020000 01000000 MOV DWORD PTR DS:[EBX+24C], 1
004C2B57 |. EB 20 JMP SHORT eXeScope.004C2B79
004C2B59 |> 6A 00 PUSH 0
004C2B5B |. 8D55 EC LEA EDX, [LOCAL.5]
004C2B5E |. B8 F02B4C00 MOV EAX, eXeScope.004C2BF0 ; 无效的id 或名字
004C2B63 |. E8 680D0000 CALL eXeScope.004C38D0
004C2B68 |. 8B45 EC MOV EAX, [LOCAL.5] ; |
004C2B6B |. 66:8B0D 202C4C00 MOV CX, WORD PTR DS:[4C2C20] ; |
004C2B72 |. B2 01 MOV DL, 1 ; |
004C2B74 |. E8 2F4BF7FF CALL eXeScope.004376A8 ; \eXeScope.004376A8
仔细观察这段代码,发现地址004C2B59处PUSH的数据是用于显示“无效的ID或名字”对话框的起始参数,上面(地址004C2B57)一句JMP指令则跳过了这一段,与此形成了一个分水岭;故而再往上看,看看有哪条指令会跳转到地址004C2B59的push指令处(也就是注册失败的处理逻辑处),发现是地址004C2AC6处的JE指令,这就说明前面地址004C2ABF处的CALL函数调用,如果返回值为0的话,则表明注册操作失败,因而此函数值得重点对待(对其下断点);然后再在本函数起始地址004C2A55处下断点,随便在注册框中输入数据(如NAME:111,ID:222);随后单击确定按钮,不出意料断在了函数起始地址004C2A55处,接下来我们再F8单步跟踪至地址004C2ABF处,单步的过程中观察寄存器的变化,发现前面的代码主要是用于获取用户在注册对话框中输入的内容;最后F7进入我们需要重点关注的函数内部;
地址004C2ABF处CALL的函数的具体实现如下:
004CBF7C /$ 55 PUSH EBP
004CBF7D |. 8BEC MOV EBP, ESP
004CBF7F |. 51 PUSH ECX
004CBF80 |. 53 PUSH EBX
004CBF81 |. 8955 FC MOV [LOCAL.1], EDX
004CBF84 |. 8B45 FC MOV EAX, [LOCAL.1]
004CBF87 |. E8 B48EF3FF CALL eXeScope.00404E40
004CBF8C |. 33C0 XOR EAX, EAX
004CBF8E |. 55 PUSH EBP
004CBF8F |. 68 1BC04C00 PUSH eXeScope.004CC01B
004CBF94 |. 64:FF30 PUSH DWORD PTR FS:[EAX]
004CBF97 |. 64:8920 MOV DWORD PTR FS:[EAX], ESP
004CBF9A |. 33DB XOR EBX, EBX
004CBF9C |. 8B45 FC MOV EAX, [LOCAL.1]
004CBF9F |. E8 AC8CF3FF CALL eXeScope.00404C50
004CBFA4 |. 83F8 0A CMP EAX, 0A
004CBFA7 |. 75 5C JNZ SHORT eXeScope.004CC005
004CBFA9 |. 8B55 FC MOV EDX, [LOCAL.1]
004CBFAC |. B8 30C04C00 MOV EAX, eXeScope.004CC030 ; a1910
004CBFB1 |. E8 DE8FF3FF CALL eXeScope.00404F94
004CBFB6 |. 48 DEC EAX
004CBFB7 |. 74 10 JE SHORT eXeScope.004CBFC9
004CBFB9 |. 8B55 FC MOV EDX, [LOCAL.1]
004CBFBC |. B8 40C04C00 MOV EAX, eXeScope.004CC040 ; a1423
004CBFC1 |. E8 CE8FF3FF CALL eXeScope.00404F94
004CBFC6 |. 48 DEC EAX
004CBFC7 |. 75 3C JNZ SHORT eXeScope.004CC005
004CBFC9 |> B8 02000000 MOV EAX, 2
004CBFCE |> 8B55 FC /MOV EDX, [LOCAL.1]
004CBFD1 |. 8A5402 FF |MOV DL, BYTE PTR DS:[EDX+EAX-1]
004CBFD5 |. 80FA 30 |CMP DL, 30
004CBFD8 |. 72 2B |JB SHORT eXeScope.004CC005
004CBFDA |. 80FA 39 |CMP DL, 39
004CBFDD |. 77 26 |JA SHORT eXeScope.004CC005
004CBFDF |. 40 |INC EAX
004CBFE0 |. 83F8 0B |CMP EAX, 0B
004CBFE3 |.^ 75 E9 \JNZ SHORT eXeScope.004CBFCE
004CBFE5 |. 8B45 FC MOV EAX, [LOCAL.1]
004CBFE8 |. 0FB640 08 MOVZX EAX, BYTE PTR DS:[EAX+8]
004CBFEC |. 8B55 FC MOV EDX, [LOCAL.1]
004CBFEF |. 0FB652 09 MOVZX EDX, BYTE PTR DS:[EDX+9]
004CBFF3 |. 03C2 ADD EAX, EDX
004CBFF5 |. B9 0A000000 MOV ECX, 0A
004CBFFA |. 33D2 XOR EDX, EDX
004CBFFC |. F7F1 DIV ECX
004CBFFE |. 83FA 04 CMP EDX, 4
004CC001 |. 75 02 JNZ SHORT eXeScope.004CC005
004CC003 |. B3 01 MOV BL, 1
004CC005 |> 33C0 XOR EAX, EAX
004CC007 |. 5A POP EDX ; eXeScope.004C2AC4
004CC008 |. 59 POP ECX ; eXeScope.004C2AC4
004CC009 |. 59 POP ECX ; eXeScope.004C2AC4
004CC00A |. 64:8910 MOV DWORD PTR FS:[EAX], EDX
004CC00D |. 68 22C04C00 PUSH eXeScope.004CC022
004CC012 |> 8D45 FC LEA EAX, [LOCAL.1]
004CC015 |. E8 7689F3FF CALL eXeScope.00404990
004CC01A \. C3 RETN
004CC01B .^ E9 5483F3FF JMP eXeScope.00404374
004CC020 .^ EB F0 JMP SHORT eXeScope.004CC012
004CC022 . 8BC3 MOV EAX, EBX
004CC024 . 5B POP EBX ; eXeScope.004C2AC4
004CC025 . 59 POP ECX ; eXeScope.004C2AC4
004CC026 . 5D POP EBP ; eXeScope.004C2AC4
004CC027 . C3 RETN
大致观察一下,并F8单步执行几遍看看流程,发现输入的ID长度如果不是10(0A),就会通过地址004CBFA7处的JNZ指令直接跳过一大段代码后直接返回(返回值为0),导致上层认为失败;所以我们接下来需要构造长度为10的ID试试,如ID:0123456789;此时我们能顺利进入地址004CBFA9处,发现此处指令旁边有2个比较明显的字符串参考注释:a1910和a1423;并且下面指令CALL eXeScope.00404F94之后,如果返回值EAX为1,都会直接进入地址004CBFC9处,否则跟ID长度不为10的命运一样;所以我们需要进去看下eXeScope.00404F94究竟做什么,才能导致EAX为1;
函数eXeScope.00404F94的具体实现如下:
00404F94 /$ 85C0 TEST EAX, EAX
00404F96 |. 74 40 JE SHORT eXeScope.00404FD8
00404F98 |. 85D2 TEST EDX, EDX
00404F9A |. 74 31 JE SHORT eXeScope.00404FCD
00404F9C |. 53 PUSH EBX
00404F9D |. 56 PUSH ESI ; eXeScope.0046B5B0
00404F9E |. 57 PUSH EDI
00404F9F |. 89C6 MOV ESI, EAX
00404FA1 |. 89D7 MOV EDI, EDX
00404FA3 |. 8B4F FC MOV ECX, DWORD PTR DS:[EDI-4]
00404FA6 |. 57 PUSH EDI
00404FA7 |. 8B56 FC MOV EDX, DWORD PTR DS:[ESI-4]
00404FAA |. 4A DEC EDX
00404FAB |. 78 1B JS SHORT eXeScope.00404FC8
00404FAD |. 8A06 MOV AL, BYTE PTR DS:[ESI]
00404FAF |. 46 INC ESI ; eXeScope.0046B5B0
00404FB0 |. 29D1 SUB ECX, EDX
00404FB2 |. 7E 14 JLE SHORT eXeScope.00404FC8
00404FB4 |> F2:AE /REPNE SCAS BYTE PTR ES:[EDI]
00404FB6 |. 75 10 |JNZ SHORT eXeScope.00404FC8
00404FB8 |. 89CB |MOV EBX, ECX
00404FBA |. 56 |PUSH ESI ; eXeScope.0046B5B0
00404FBB |. 57 |PUSH EDI
00404FBC |. 89D1 |MOV ECX, EDX
00404FBE |. F3:A6 |REPE CMPS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI]
00404FC0 |. 5F |POP EDI ; 0012F26C
00404FC1 |. 5E |POP ESI ; 0012F26C
00404FC2 |. 74 0C |JE SHORT eXeScope.00404FD0
00404FC4 |. 89D9 |MOV ECX, EBX
00404FC6 |.^ EB EC \JMP SHORT eXeScope.00404FB4
00404FC8 |> 5A POP EDX ; 0012F26C
00404FC9 |. 31C0 XOR EAX, EAX
00404FCB |. EB 08 JMP SHORT eXeScope.00404FD5
00404FCD |> 31C0 XOR EAX, EAX
00404FCF |. C3 RETN
00404FD0 |> 5A POP EDX ; 0012F26C
00404FD1 |. 89F8 MOV EAX, EDI
00404FD3 |. 29D0 SUB EAX, EDX
00404FD5 |> 5F POP EDI ; 0012F26C
00404FD6 |. 5E POP ESI ; 0012F26C
00404FD7 |. 5B POP EBX ; 0012F26C
00404FD8 \> C3 RETN
F7进入此函数后,F8单步跟踪至地址00404FB6处的JNZ指令后,发现执行流程直接跳过大段的指令返回了(返回值为0,不是我们期望的1);此时通过观察代码及寄存器发现,ID中需要包含字母A;OK,在JNZ处下断点,然后我们重新构造我们的ID,使其为A123456789,按F9再来一遍,随后顺利通过JNZ指令;但是接下来还是直接执行到了地址00404FC8处的指令,也即ID未包含字母A时跳转到的地方;仔细观看00404FB8至00404FC6处的指令细节,发现字母A之后的字符要跟传入的字符串A1910后面的1910匹配才行;OK,那我们继续按照要求构造我们的ID,使其为A191012345,再来一遍后发现顺利通过此函数,并且返回值被置为1,同时函数返回后跳转至地址004CBFC9处,执行接下来的指令;按F8继续单步跟踪,发现我们通过了一个用于验证第2个至第10个字符是否为数字的指令段,看来我们构造的A191012345在这部分走了*运,呵呵;继续跟踪接下来的代码,发现指令中要求ID中的第9个字符与第10个字符的ASCII码值加起来被10(0A)除后,还要余4(见地址004CBFFE处指令),否则也直接跳至失败处(地址004CC005),如同ID长度不为10一样的处理;因而我们还得按照指令要求继续构造我们的ID,使其满足上面的要求,接下来我们把其改为A191012344,使最后二个字符加起来刚好满足要求;符合要求后单步跟踪来到地址004CC001处,并继续跟踪,直至返回至地址004C2AC4处,发现到目前为止还算顺利;继续F8至地址004C2B57处的指令,发现顺起来后,真的一路顺风了;
OK,此时大着胆子,按F9让程序直接跑起来,发现注册框突然消失了,心想难道失败了?但是重新点击注册按钮,却惊喜的发现我们注册成功了,O(∩_∩)O~ 具体见下图:
松口气后,我们可以再接再厉,仔细阅读下上述的三段代码,就可以逆向出注册算法,同时也知道注册的内容是放在eXeScope.ini文件中的,Y的还是明文的(如下图),o(╯□╰)o
作者:nopnopnop
1、自我纪念一下,身为菜鸟的我在无任何参考下的破解处女作;
2、写完之后,发现破解这个程序的分析文章已经“烂大街”了,但是我还是希望能给目前跟我一样菜的人,有所帮助,因为这里面包含了一些分析过程(心理描写),不像高手或者教材写的那样,基本上都是一下就直指问题核心,在我看来都是没有任何理由似的神来之笔,让我有些迷茫:高手是神,不是人;亲,那身为人的我该怎么办,这不是没法混了嘛?当然我明白这些不关键的理由在高手眼里也许不重要,同时写出来显得非常繁琐,但是对于目前身为菜鸟的我,我觉着这样写出来比较重要,这样不但能让我从细节中能学到更多的东西,同时让我知道高手应该是人,不是神,身为菜鸟的我还有希望赶上;所以我很繁琐的写出来,希望能帮助那些跟我有相同疑惑的同学;
PS:写出的内容基本上包含了我整个破解的过程及想法,很繁琐,有兴趣的可以当小说看看,一笑置之!如果各位觉着文中言语有冒犯之处,请多多谅解!
破解缘由:
这段时间在学习《加密与解密》第13章脱壳技术的时候,碰到2件事:
1、以前电脑上装了一个“文件夹加密”软件,但是有使用限制,所以很早就想实战破解一下;但是发现此软件是加壳处理过的,而当时我又完全不会手工脱壳,就想留着以后给自己实践用;恰巧这几天学到一点脱壳技术,就想实战一下,Y的失败了,信心大受打击;心想着后面还有好几章讲软件保护的,可能看完之后再去脱壳好点,故自我安慰后暂时放下了;
2、在练习PE文件优化操作时,打算用eXeScope(版本6.50)工具看看优化后的脱壳程序资源能不能被正常编辑,谁知二次操作后出现如下提示:
感觉有点倒霉,不过心中也有种喜悦之情在弥漫,因为又找到理由以及合适的软件去练下手了(目前个人时间安排比较紧,所以我认为去破解其它仅仅是为了练手目的而准备的软件来说,这种对我来说更有实用价值而已,勿怪);
破解过程:
首先用PEID看看该软件有没有加过壳(见下图),发现运气好,这个软件没加壳,所以心理负担少了一点,但是发现该软件是通过Delphi写的,又有点蛋疼起来了(因为本人Delphi没接触过),不过仔细想想破解跟语言关系应该不大,并且假设你只破解熟悉的语言写的程序,那还搞个屁呀,所以继续;
首先经过简单查找之后,发现注册功能是帮助菜单的菜单项,点击随便试用后,结果如下:
在输入错误的名字(111)跟ID(222)后,出现了“无效的ID或名字”这样一个字符串;
然后用Ollydbg加载eXeScope程序,并查找“无效的ID或名字”,神奇的是查找失败了(原因下文会提及);我勒个去,然后再查找“你的名字”等其他比较接近的字符串,也均以失败告终,当时就有点蒙了;随后又试了对CreateWindow,TranslateMessage,以及消息断点等等我能想到的方法去尝试,的确断点进来了,但是来到用户代码模块后,依然很迷茫;因为都ret了好几次,还是没找到处理注册逻辑的代码块;想想不会这么倒霉吧,第二次练手又失败,这打击没法接受呀!
已近中午,就跑去吃饭,期间仔细想了想,确定了几件事:
1、这一次破解必须要成功,因为连续失败影响太大;
2、没有出现的字符串可能包含在资源文件中,可以试着以资源方式打开此文件看看;随后吃完饭后就这么做了,见下图:
果然这个东西包含在一个字符串名为“TFReg”的对象中;Ok,感觉出现了部分曙光,随后就查找“TFReg”这个字符串,还好这个找到了,然后对这个数据地址下硬件断点;断过去之后,发现来到的地方离我预期的地方差的还是很远,至少向上返回好几层之后,都没找到;
没办法,在“必须搞定”的这种压力下,目前只能一步一步跟踪,基本上每次call都进去瞄了眼,不断的重复试验;皇天不负有心人,2个多小时候后,终于被我*运的找到关键代码处(因为看到自己输入的字符串,同时还出现了“无效的ID或名称”),接下来就比较顺水了;至此得出的结论是一定要给自己压力;
破解之后,当时就觉着奇怪,为什么我搜索“无效的ID或名称”找不到,然后自己就人工去查找这个字符串,竟然被找到了,暗想难道是Ollydbg自带的查找功能有bug;多次试验后,才悲剧的发现“ID”前后存在空格;此处又得到一个经验:虽然打字不费力,但是以后查找字符串时,还是别打全了,O__O”…;
接下来就试着按常规思路去破解(查找关键字符串方式),也就是下面写的具体破解内容,随后常规方式也搞定了;这时想把第一次误打误撞方式破解找到代码关键点的过程再试验总结下,看能不能得出什么经验教训,不料此时却重复不出来了,原因应该是那种方式本来就不靠谱,同时已经通过常规查找成功,导致没有精力再来一遍;
以下是采用常规模式算出序列号(ID)的具体过程:
用Ollydbg加载eXeScope程序并按F9运行,随后按Ctrl+G输入跳转地址跳转到用户代码模块处,然后采用“超级字符串参考插件”查找相关字符串,见下图:
因为找出来的字符串比较多,所以直接搜索下“无效的”这几个字,找到我们希望的字符串,见下图:(如果用“无效的ID ”查找,千万别漏掉ID二个字符二边的空格,不然就找不到了)
双击找到的字符串,跳转到所引用的代码处,具体地址为004C2B5E,相关代码如下:
004C2A55 |. 55 PUSH EBP
004C2A56 |. 68 A12B4C00 PUSH eXeScope.004C2BA1
004C2A5B |. 64:FF30 PUSH DWORD PTR FS:[EAX]
004C2A5E |. 64:8920 MOV DWORD PTR FS:[EAX], ESP
004C2A61 |. A1 5CFC4C00 MOV EAX, DWORD PTR DS:[4CFC5C]
004C2A66 |. 8038 00 CMP BYTE PTR DS:[EAX], 0
004C2A69 |. 74 0F JE SHORT eXeScope.004C2A7A
004C2A6B |. C783 4C020000 02000000 MOV DWORD PTR DS:[EBX+24C], 2
004C2A75 |. E9 FF000000 JMP eXeScope.004C2B79
004C2A7A |> 8D55 FC LEA EDX, [LOCAL.1]
004C2A7D |. 8B83 F8020000 MOV EAX, DWORD PTR DS:[EBX+2F8]
004C2A83 |. E8 F4F8FAFF CALL eXeScope.0047237C
004C2A88 |. 8B55 FC MOV EDX, [LOCAL.1]
004C2A8B |. A1 E8FE4C00 MOV EAX, DWORD PTR DS:[4CFEE8]
004C2A90 |. E8 4F1FF4FF CALL eXeScope.004049E4
004C2A95 |. 8D55 F8 LEA EDX, [LOCAL.2]
004C2A98 |. 8B83 FC020000 MOV EAX, DWORD PTR DS:[EBX+2FC]
004C2A9E |. E8 D9F8FAFF CALL eXeScope.0047237C
004C2AA3 |. 8B55 F8 MOV EDX, [LOCAL.2] ; kernel32.7C817080
004C2AA6 |. A1 4CFE4C00 MOV EAX, DWORD PTR DS:[4CFE4C]
004C2AAB |. E8 341FF4FF CALL eXeScope.004049E4
004C2AB0 |. 8B15 4CFE4C00 MOV EDX, DWORD PTR DS:[4CFE4C] ; eXeScope.004D2E58
004C2AB6 |. 8B12 MOV EDX, DWORD PTR DS:[EDX]
004C2AB8 |. A1 54FC4C00 MOV EAX, DWORD PTR DS:[4CFC54]
004C2ABD |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2ABF |. E8 B8940000 CALL eXeScope.004CBF7C
004C2AC4 |. 84C0 TEST AL, AL
004C2AC6 |. 0F84 8D000000 JE eXeScope.004C2B59
004C2ACC |. A1 E8FE4C00 MOV EAX, DWORD PTR DS:[4CFEE8]
004C2AD1 |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2AD3 |. E8 7821F4FF CALL eXeScope.00404C50
004C2AD8 |. 85C0 TEST EAX, EAX
004C2ADA |. 7E 7D JLE SHORT eXeScope.004C2B59
004C2ADC |. 8D55 F0 LEA EDX, [LOCAL.4]
004C2ADF |. A1 FCFE4C00 MOV EAX, DWORD PTR DS:[4CFEFC]
004C2AE4 |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2AE6 |. E8 11FCFCFF CALL eXeScope.004926FC
004C2AEB |. 8B45 F0 MOV EAX, [LOCAL.4]
004C2AEE |. 8D4D F4 LEA ECX, [LOCAL.3]
004C2AF1 |. BA B82B4C00 MOV EDX, eXeScope.004C2BB8 ; .ini
004C2AF6 |. E8 2570F4FF CALL eXeScope.00409B20
004C2AFB |. 8B4D F4 MOV ECX, [LOCAL.3] ; kernel32._except_handler3
004C2AFE |. B2 01 MOV DL, 1
004C2B00 |. A1 2CBE4300 MOV EAX, DWORD PTR DS:[43BE2C]
004C2B05 |. E8 D293F7FF CALL eXeScope.0043BEDC
004C2B0A |. 8BF0 MOV ESI, EAX
004C2B0C |. A1 E8FE4C00 MOV EAX, DWORD PTR DS:[4CFEE8]
004C2B11 |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2B13 |. 50 PUSH EAX
004C2B14 |. B9 C82B4C00 MOV ECX, eXeScope.004C2BC8 ; name
004C2B19 |. BA D82B4C00 MOV EDX, eXeScope.004C2BD8 ; reg
004C2B1E |. 8BC6 MOV EAX, ESI
004C2B20 |. 8B38 MOV EDI, DWORD PTR DS:[EAX]
004C2B22 |. FF57 04 CALL NEAR DWORD PTR DS:[EDI+4] ; ntdll.7C96F7E7
004C2B25 |. A1 4CFE4C00 MOV EAX, DWORD PTR DS:[4CFE4C]
004C2B2A |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
004C2B2C |. 50 PUSH EAX
004C2B2D |. BA D82B4C00 MOV EDX, eXeScope.004C2BD8 ; reg
004C2B32 |. B9 E42B4C00 MOV ECX, eXeScope.004C2BE4 ; id
004C2B37 |. 8BC6 MOV EAX, ESI
004C2B39 |. 8B38 MOV EDI, DWORD PTR DS:[EAX]
004C2B3B |. FF57 04 CALL NEAR DWORD PTR DS:[EDI+4] ; ntdll.7C96F7E7
004C2B3E |. 8BC6 MOV EAX, ESI
004C2B40 |. E8 9B10F4FF CALL eXeScope.00403BE0
004C2B45 |. A1 5CFC4C00 MOV EAX, DWORD PTR DS:[4CFC5C]
004C2B4A |. C600 01 MOV BYTE PTR DS:[EAX], 1
004C2B4D |. C783 4C020000 01000000 MOV DWORD PTR DS:[EBX+24C], 1
004C2B57 |. EB 20 JMP SHORT eXeScope.004C2B79
004C2B59 |> 6A 00 PUSH 0
004C2B5B |. 8D55 EC LEA EDX, [LOCAL.5]
004C2B5E |. B8 F02B4C00 MOV EAX, eXeScope.004C2BF0 ; 无效的id 或名字
004C2B63 |. E8 680D0000 CALL eXeScope.004C38D0
004C2B68 |. 8B45 EC MOV EAX, [LOCAL.5] ; |
004C2B6B |. 66:8B0D 202C4C00 MOV CX, WORD PTR DS:[4C2C20] ; |
004C2B72 |. B2 01 MOV DL, 1 ; |
004C2B74 |. E8 2F4BF7FF CALL eXeScope.004376A8 ; \eXeScope.004376A8
仔细观察这段代码,发现地址004C2B59处PUSH的数据是用于显示“无效的ID或名字”对话框的起始参数,上面(地址004C2B57)一句JMP指令则跳过了这一段,与此形成了一个分水岭;故而再往上看,看看有哪条指令会跳转到地址004C2B59的push指令处(也就是注册失败的处理逻辑处),发现是地址004C2AC6处的JE指令,这就说明前面地址004C2ABF处的CALL函数调用,如果返回值为0的话,则表明注册操作失败,因而此函数值得重点对待(对其下断点);然后再在本函数起始地址004C2A55处下断点,随便在注册框中输入数据(如NAME:111,ID:222);随后单击确定按钮,不出意料断在了函数起始地址004C2A55处,接下来我们再F8单步跟踪至地址004C2ABF处,单步的过程中观察寄存器的变化,发现前面的代码主要是用于获取用户在注册对话框中输入的内容;最后F7进入我们需要重点关注的函数内部;
地址004C2ABF处CALL的函数的具体实现如下:
004CBF7C /$ 55 PUSH EBP
004CBF7D |. 8BEC MOV EBP, ESP
004CBF7F |. 51 PUSH ECX
004CBF80 |. 53 PUSH EBX
004CBF81 |. 8955 FC MOV [LOCAL.1], EDX
004CBF84 |. 8B45 FC MOV EAX, [LOCAL.1]
004CBF87 |. E8 B48EF3FF CALL eXeScope.00404E40
004CBF8C |. 33C0 XOR EAX, EAX
004CBF8E |. 55 PUSH EBP
004CBF8F |. 68 1BC04C00 PUSH eXeScope.004CC01B
004CBF94 |. 64:FF30 PUSH DWORD PTR FS:[EAX]
004CBF97 |. 64:8920 MOV DWORD PTR FS:[EAX], ESP
004CBF9A |. 33DB XOR EBX, EBX
004CBF9C |. 8B45 FC MOV EAX, [LOCAL.1]
004CBF9F |. E8 AC8CF3FF CALL eXeScope.00404C50
004CBFA4 |. 83F8 0A CMP EAX, 0A
004CBFA7 |. 75 5C JNZ SHORT eXeScope.004CC005
004CBFA9 |. 8B55 FC MOV EDX, [LOCAL.1]
004CBFAC |. B8 30C04C00 MOV EAX, eXeScope.004CC030 ; a1910
004CBFB1 |. E8 DE8FF3FF CALL eXeScope.00404F94
004CBFB6 |. 48 DEC EAX
004CBFB7 |. 74 10 JE SHORT eXeScope.004CBFC9
004CBFB9 |. 8B55 FC MOV EDX, [LOCAL.1]
004CBFBC |. B8 40C04C00 MOV EAX, eXeScope.004CC040 ; a1423
004CBFC1 |. E8 CE8FF3FF CALL eXeScope.00404F94
004CBFC6 |. 48 DEC EAX
004CBFC7 |. 75 3C JNZ SHORT eXeScope.004CC005
004CBFC9 |> B8 02000000 MOV EAX, 2
004CBFCE |> 8B55 FC /MOV EDX, [LOCAL.1]
004CBFD1 |. 8A5402 FF |MOV DL, BYTE PTR DS:[EDX+EAX-1]
004CBFD5 |. 80FA 30 |CMP DL, 30
004CBFD8 |. 72 2B |JB SHORT eXeScope.004CC005
004CBFDA |. 80FA 39 |CMP DL, 39
004CBFDD |. 77 26 |JA SHORT eXeScope.004CC005
004CBFDF |. 40 |INC EAX
004CBFE0 |. 83F8 0B |CMP EAX, 0B
004CBFE3 |.^ 75 E9 \JNZ SHORT eXeScope.004CBFCE
004CBFE5 |. 8B45 FC MOV EAX, [LOCAL.1]
004CBFE8 |. 0FB640 08 MOVZX EAX, BYTE PTR DS:[EAX+8]
004CBFEC |. 8B55 FC MOV EDX, [LOCAL.1]
004CBFEF |. 0FB652 09 MOVZX EDX, BYTE PTR DS:[EDX+9]
004CBFF3 |. 03C2 ADD EAX, EDX
004CBFF5 |. B9 0A000000 MOV ECX, 0A
004CBFFA |. 33D2 XOR EDX, EDX
004CBFFC |. F7F1 DIV ECX
004CBFFE |. 83FA 04 CMP EDX, 4
004CC001 |. 75 02 JNZ SHORT eXeScope.004CC005
004CC003 |. B3 01 MOV BL, 1
004CC005 |> 33C0 XOR EAX, EAX
004CC007 |. 5A POP EDX ; eXeScope.004C2AC4
004CC008 |. 59 POP ECX ; eXeScope.004C2AC4
004CC009 |. 59 POP ECX ; eXeScope.004C2AC4
004CC00A |. 64:8910 MOV DWORD PTR FS:[EAX], EDX
004CC00D |. 68 22C04C00 PUSH eXeScope.004CC022
004CC012 |> 8D45 FC LEA EAX, [LOCAL.1]
004CC015 |. E8 7689F3FF CALL eXeScope.00404990
004CC01A \. C3 RETN
004CC01B .^ E9 5483F3FF JMP eXeScope.00404374
004CC020 .^ EB F0 JMP SHORT eXeScope.004CC012
004CC022 . 8BC3 MOV EAX, EBX
004CC024 . 5B POP EBX ; eXeScope.004C2AC4
004CC025 . 59 POP ECX ; eXeScope.004C2AC4
004CC026 . 5D POP EBP ; eXeScope.004C2AC4
004CC027 . C3 RETN
大致观察一下,并F8单步执行几遍看看流程,发现输入的ID长度如果不是10(0A),就会通过地址004CBFA7处的JNZ指令直接跳过一大段代码后直接返回(返回值为0),导致上层认为失败;所以我们接下来需要构造长度为10的ID试试,如ID:0123456789;此时我们能顺利进入地址004CBFA9处,发现此处指令旁边有2个比较明显的字符串参考注释:a1910和a1423;并且下面指令CALL eXeScope.00404F94之后,如果返回值EAX为1,都会直接进入地址004CBFC9处,否则跟ID长度不为10的命运一样;所以我们需要进去看下eXeScope.00404F94究竟做什么,才能导致EAX为1;
函数eXeScope.00404F94的具体实现如下:
00404F94 /$ 85C0 TEST EAX, EAX
00404F96 |. 74 40 JE SHORT eXeScope.00404FD8
00404F98 |. 85D2 TEST EDX, EDX
00404F9A |. 74 31 JE SHORT eXeScope.00404FCD
00404F9C |. 53 PUSH EBX
00404F9D |. 56 PUSH ESI ; eXeScope.0046B5B0
00404F9E |. 57 PUSH EDI
00404F9F |. 89C6 MOV ESI, EAX
00404FA1 |. 89D7 MOV EDI, EDX
00404FA3 |. 8B4F FC MOV ECX, DWORD PTR DS:[EDI-4]
00404FA6 |. 57 PUSH EDI
00404FA7 |. 8B56 FC MOV EDX, DWORD PTR DS:[ESI-4]
00404FAA |. 4A DEC EDX
00404FAB |. 78 1B JS SHORT eXeScope.00404FC8
00404FAD |. 8A06 MOV AL, BYTE PTR DS:[ESI]
00404FAF |. 46 INC ESI ; eXeScope.0046B5B0
00404FB0 |. 29D1 SUB ECX, EDX
00404FB2 |. 7E 14 JLE SHORT eXeScope.00404FC8
00404FB4 |> F2:AE /REPNE SCAS BYTE PTR ES:[EDI]
00404FB6 |. 75 10 |JNZ SHORT eXeScope.00404FC8
00404FB8 |. 89CB |MOV EBX, ECX
00404FBA |. 56 |PUSH ESI ; eXeScope.0046B5B0
00404FBB |. 57 |PUSH EDI
00404FBC |. 89D1 |MOV ECX, EDX
00404FBE |. F3:A6 |REPE CMPS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI]
00404FC0 |. 5F |POP EDI ; 0012F26C
00404FC1 |. 5E |POP ESI ; 0012F26C
00404FC2 |. 74 0C |JE SHORT eXeScope.00404FD0
00404FC4 |. 89D9 |MOV ECX, EBX
00404FC6 |.^ EB EC \JMP SHORT eXeScope.00404FB4
00404FC8 |> 5A POP EDX ; 0012F26C
00404FC9 |. 31C0 XOR EAX, EAX
00404FCB |. EB 08 JMP SHORT eXeScope.00404FD5
00404FCD |> 31C0 XOR EAX, EAX
00404FCF |. C3 RETN
00404FD0 |> 5A POP EDX ; 0012F26C
00404FD1 |. 89F8 MOV EAX, EDI
00404FD3 |. 29D0 SUB EAX, EDX
00404FD5 |> 5F POP EDI ; 0012F26C
00404FD6 |. 5E POP ESI ; 0012F26C
00404FD7 |. 5B POP EBX ; 0012F26C
00404FD8 \> C3 RETN
F7进入此函数后,F8单步跟踪至地址00404FB6处的JNZ指令后,发现执行流程直接跳过大段的指令返回了(返回值为0,不是我们期望的1);此时通过观察代码及寄存器发现,ID中需要包含字母A;OK,在JNZ处下断点,然后我们重新构造我们的ID,使其为A123456789,按F9再来一遍,随后顺利通过JNZ指令;但是接下来还是直接执行到了地址00404FC8处的指令,也即ID未包含字母A时跳转到的地方;仔细观看00404FB8至00404FC6处的指令细节,发现字母A之后的字符要跟传入的字符串A1910后面的1910匹配才行;OK,那我们继续按照要求构造我们的ID,使其为A191012345,再来一遍后发现顺利通过此函数,并且返回值被置为1,同时函数返回后跳转至地址004CBFC9处,执行接下来的指令;按F8继续单步跟踪,发现我们通过了一个用于验证第2个至第10个字符是否为数字的指令段,看来我们构造的A191012345在这部分走了*运,呵呵;继续跟踪接下来的代码,发现指令中要求ID中的第9个字符与第10个字符的ASCII码值加起来被10(0A)除后,还要余4(见地址004CBFFE处指令),否则也直接跳至失败处(地址004CC005),如同ID长度不为10一样的处理;因而我们还得按照指令要求继续构造我们的ID,使其满足上面的要求,接下来我们把其改为A191012344,使最后二个字符加起来刚好满足要求;符合要求后单步跟踪来到地址004CC001处,并继续跟踪,直至返回至地址004C2AC4处,发现到目前为止还算顺利;继续F8至地址004C2B57处的指令,发现顺起来后,真的一路顺风了;
OK,此时大着胆子,按F9让程序直接跑起来,发现注册框突然消失了,心想难道失败了?但是重新点击注册按钮,却惊喜的发现我们注册成功了,O(∩_∩)O~ 具体见下图:
松口气后,我们可以再接再厉,仔细阅读下上述的三段代码,就可以逆向出注册算法,同时也知道注册的内容是放在eXeScope.ini文件中的,Y的还是明文的(如下图),o(╯□╰)o
作者:nopnopnop