首页
社区
课程
招聘
[原创]战胜vb经典编程.exe
发表于: 2007-2-11 15:30 8566

[原创]战胜vb经典编程.exe

2007-2-11 15:30
8566

我用这些工具,假使你也使用它们。
查壳工具PEID。
动态调戏器OD。
今日从某个网站载来一些书,可是呢?现在的作者忒抠门些,说:“你前面的看好了,不收你钱。”言下之意就是后面的就要RMB了,或者干一些比付钱更加痛苦的事情也可以得到一个阅读码。可我是穷人啊!再说我是cracker啊!自己动手丰衣足食!
越来越习惯于OD的强大,所以,一发现它没有壳,我就用OD开始调戏它了!
本来,一个delphi的程序应该用dede来分析。可是作者尽是用了一些不可视化的表达unit1,unit2等等,所以DD不好分析。我就顺便用DD输出了一个map文件供OD用(输出->ida/softice的map/sym文件,在输出文件下填好路径―>输出文件),OD的loadmap插件载入它,其实这点干与不干一个样。没用!但这是一个好习惯,而且看起软件来更加清楚。这里没用不表示所有地方都没用。你记下了吗?
一载入,就是查找字符串。
/*4891A9*/  MOV EDX,vb经典编.004892DC  
……代表若干行代码
/*48C3E0*/  MOV EDX,vb经典编.0048C494  //  机器码:
/*48C3E5*/  CALL vb经典编.00403DC4  //->system.@LStrCat3;这是输入map文件后多出来的注释
/*48C3EA*/  LEA EDX,DWORD PTR SS:[EBP-10]
……
/*48C3FC*/  LEA EAX,DWORD PTR SS:[EBP-14]
/*48C3FF*/  MOV ECX,vb经典编.0048C4A8  //-阅读密码
……
/*495017*/  MOV ECX,vb经典编.004950F4  //提示
/*49501C*/  MOV EDX,vb经典编.0049517C  //现在可阅读全部目录了!
/*495021*/  MOV EAX,DWORD PTR DS:[4A0A80]
……
/*49502F*/  PUSH 0
/*495031*/  MOV ECX,vb经典编.004950F4  //提示
/*495036*/  MOV EDX,vb经典编.00495194  //阅读文书密码错误!
还有一些“文件已被非法改动,不能打开!”“异常一”等也告诉我们,可能有自校验。首先当然是爆破试试,因为简单。根据上面的,感觉随便找一点理论上都可以实现爆破。当然在失败之后,我放弃了,你也还是快快放弃吧!毕竟校验不是盖的。我对自己说,还是序列号更现实。
OD载入它,有异常不管,直接Shift+F9,记得吗?很多次之后我们来到的是kernel32的领空。因为是DELPHI写的,那么先请你看如下的文字:
Q:DELPHI、C++ Builder编译的软件用GetWindowText等断点拦不住?
A:这是因为DELPHI通过向Edit发送WM_GETTEXT(直接调用WNDProc,而没有
使用消息函数)消息来获得Text的内容的,整个过程没有调用过任何Win32 API函数。所以常用的GetDlgItemTextA、GetWindowTextA等断点失效是当然的。那么如何才能将用户输入的字符串拷贝到软件的缓冲区中时使OD中断呢?办法有多种,例如用DeDe反编译得到该事件的地址,对此地址设断拦截。
懒人啦,我是啦。
好了,点击最下面那一章。出现一个提示注册的框,如图1


图1

输入123789。
好吧!既然我们心爱的GetWindowTextA是不能断了的,那么MessageBoxA还是可以的。真的下断MessageBoxA吗?当然我不会选择MessageBoxA,更好的是用apibreak插件下断万能断点。MessageBoxA要从后面找前面,而万能断点是从前面顺着调试一直走下来!这里要说明一点,有些人看到万能断点出来后有一个API叫CallWindowProcA,就认为可以达到同样的效果,那么在你试过之后就会发现不可以。因为每次选择这个软件它就会被调用,所以根本来不及看到软件的面目就又被OD断下了。还有假如你要断CallWindowProcA,如果你现在直接按ctrl+n的话那么你是不会看见CallWindowProcA的,因为我们现在在的是kernel32的领空,而CallWindowProcA很不好意思的是user32的函数。你可以用命令框,输入bp  CallWindowProcA。或者ctrl+g(转到――>表达式),输入49E12C(这是它的入口点,你可以用stud_pe看看)。现在ctrl+n才可以看见这个函数。
用插件apibreak下万能断点。点击确定,断下后取消万能断点。
/*494FC2*/  CALL vb经典编.0042F9B8
/*494FC7*/  CMP BYTE PTR DS:[EBX+28215],0C7;<――慢慢出来之后在这里,因为刚才的都只是在平衡堆栈而已。这里F2下一个断点。防止待会儿万一程序跑飞又要重新下万能断点。这都是好习惯。
/*494FCE*/  JBE SHORT vb经典编.00494FF2
在这之后气氛就渐渐浓起来了。我们慢慢的F8跟踪。眼睛看着代码窗口,寄存器窗口,数据窗口,信息窗口……
当信息窗口出现如图2所示时,表示接下来有事情要发生了。还不明白,这个一长串不就是图1中所示的机器码吗?看来不远处就会有结果了。


图2

往下看
/*495006*/  CALL vb经典编.00403E88
/*49500B*/  JNZ SHORT vb经典编.0049502F
……省略一些无用代码
/*495028*/  CALL vb经典编.0044DEF0
/*49502D*/  JMP SHORT vb经典编.00495047
看到这个不知道你有没有感触上面一个jnz和下面的jmp是相克的,上面的跳走就不会有下面的跳,上面的不跳下面的就跳了。虽然说还有很多的call,但是只有这两个这么有趣的。我们直接运行到49500B。OD的跳转变红显示它要跳,我假设这里是关键跳转。因为我输入的伪码肯定是错的,所以我不能让它从这里跳走。所以我们修改Z标志位(看到Z没有,就在寄存器窗口中)。在Z标志位上双击,代码窗口中本来红色的跳转变成了灰色,说明它不会跳走了,现在我们就直接F9(运行)看看会有什么结果。用图画更加有说服力。如图3


图3

这只是成功的第一步。虽然就像它显示的一样现在我们可阅读全部目录了,但是每次都这个操作一次简直就是锻炼我们的耐性。我们再接再厉。
现在我们ctrl+F2从新来过。知道了495006这个是比较关键的call。前面一共还有四个call,其中一个在我们F8调戏的时候明确可以知道这个call是取得伪码,这点很重要。顺便说一下delphi的特征,delphi中经常拿寄存器来传值了,不像vc那样还老是用堆栈。我们分别从下往上来看。其实这个家伙是明码比较的。
/*494FFB*/  CALL vb经典编.0042F9B8;这里出来之后才第一次在信息窗口中看到伪码
/*495000*/  MOV EAX,DWORD PTR SS:[EBP-4C]
/*495003*/  MOV EDX,DWORD PTR SS:[EBP-4]
/*495006*/  CALL vb经典编.00403E88
/*49500B*/  JNZ SHORT vb经典编.0049502F
根据494FFB处这个call的特殊性,我们基本上可以确定了,495006这是一个关键call因为想想也知道要是没有伪码出现就一切都处理好了,那么要注册码何用?如何来判断是否注册呢?所以上面代码中赋给EAX,EDX的值就非常关键了。F8走过之后发现EAX指向的内存地址的值是伪码,而EDX不用说了吧,就是指向注册码的地址了,我这边的值是“,1?_H$h30”引号不包括在内。不难猜想,前面有一些代码是在根据机器码生成重要数据,而下面的一个call呢,则是在进行比较。此刻我们来看看它们是怎么比较的。我们分三块来看这个貌似不起眼的比较。我觉得这里的比较很有趣,所以想谈谈。而且我本来期待着可以找出更多的可用注册码?在仔细分析了这些代码之后我就知道不可能了。
(一)这里我们要关注的是EDX的值的产生。
/*403E9F*/  MOV EAX,DWORD PTR DS:[ESI-4];这是伪码长度赋给EAX
/*403EA2*/  MOV EDX,DWORD PTR DS:[EDI-4];这是真码长度赋给EDX,也就是9。
/*403EA5*/  SUB EAX,EDX;这一句话其实有点致命
/*403EA7*/  JA SHORT vb经典编.00403EAB;JA的意思是高于时跳转,条件是ZF=0且CF=0。注册框最多只允许你输入9个数字。
/*403EA9*/  ADD EDX,EAX;假如上面没有跳,和403EA5这句联合在一起看,达到的效果就是EDX=EAX,而EAX的值在这里也被注定位EAX=EAX-EDX
/*403EAB*/  PUSH EDX;暂时保存一下待会儿要用。
/*403EAC*/  SHR EDX,2;相当于EDX=EDX  div  4。
/*403EAF*/  JE SHORT vb经典编.00403ED7
(二)
这是一个循环,若跳到循环外面就是死。通常明码比较的方法很多,而下面的这种我还是觉得很好玩。假如判断只有这么一些的话,那么我用“,1?_H$h3”也可以注册成功但是……下面(三)还有一重判断。
/*403EB1*/  MOV ECX,DWORD PTR DS:[ESI];ESI是伪码地址
/*403EB3*/  MOV EBX,DWORD PTR DS:[EDI];EDI是真码地址
/*403EB5*/  CMP ECX,EBX;判断前四位是否相同
/*403EB7*/  JNZ SHORT vb经典编.00403F11
/*403EB9*/  DEC EDX
/*403EBA*/  JE SHORT vb经典编.00403ED1
/*403EBC*/  MOV ECX,DWORD PTR DS:[ESI+4]
/*403EBF*/  MOV EBX,DWORD PTR DS:[EDI+4]
/*403EC2*/  CMP ECX,EBX;判断后四位是否相同
/*403EC4*/  JNZ SHORT vb经典编.00403F11
/*403EC6*/  ADD ESI,8;指针移动
/*403EC9*/  ADD EDI,8;同上,指向了最后一个字符
/*403ECC*/  DEC EDX
/*403ECD*/  JNZ SHORT vb经典编.00403EB1
(三)
/*403ECF*/  JMP SHORT vb经典编.00403ED7
/*403ED1*/  ADD ESI,4
/*403ED4*/  ADD EDI,4
/*403ED7*/  POP EDX;上面有保存的
/*403ED8*/  AND EDX,3
/*403EDB*/  JE SHORT vb经典编.00403EFF;看到这一行我本来还高兴了一下,以为可以构造一个新的注册码,谁知这条语句跳向的是AND EAX,EAX。希望破灭。
/*403EDD*/  MOV ECX,DWORD PTR DS:[ESI]
/*403EDF*/  MOV EBX,DWORD PTR DS:[EDI]
/*403EE1*/  CMP CL,BL;这里是最后的第九位判断是否相同,这里其实有一点技巧了
我们在命令框中输入d esi,看到的是这样的:00E0265C  33 00 00 00由于在内存中数据存储是逆向的,所以其实在处理中这里的值就是00 00 00 30。在d edi,00E02644  30 00 BC C7同上面的道理这里的值就是C7 BC 00 30。故 ECX= 00000030,EBX=C7BC0030。真正是我们输入的伪码只是ECX的低位即CL。所以比较时要两个低位比较。                              
/*403EE3*/  JNZ SHORT vb经典编.00403F26;是否成功就在此一举了
到这里我们也已经把它分析的差不多了。因为注册码是从一开始就躺在那里的,对于这种东西我们直接winhex找内存就可以发现序列号了。如图4



图4
这个东西的致命缺点就是明码比较,但要赞叹的一点是防爆破做得很好。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (9)
雪    币: 615
活跃值: (1222)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
楼主今天高产
2007-2-11 16:59
0
雪    币: 250
活跃值: (30)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
此文关键是:这个东西的致命缺点就是明码比较
2007-2-11 19:52
0
雪    币: 200
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
很好,又学到东西了!
2007-2-11 23:57
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
写的很好,语言生动
2007-2-12 02:26
0
雪    币: 217
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
刚来的看了看不错!!!!!!!!!!!!!
2007-2-12 05:02
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
7
哇,短小精悍,
2007-2-12 09:30
0
雪    币: 226
活跃值: (11)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
厉害厉害,佩服佩服.
2007-2-12 10:06
0
雪    币: 101
活跃值: (12)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
9
/*403E9F*/  MOV EAX,DWORD PTR DS:[ESI-4];这是伪码长度赋给EAX
/*403EA2*/  MOV EDX,DWORD PTR DS:[EDI-4];这是真码长度赋给EDX,也就是9。

整段代码其实就是2个bstr, 做比较而已

/*403EA7*/  JA SHORT vb经典编.00403EAB;JA的意思是高于时跳转,条件是ZF=0且CF=0。注册框最多只允许你输入9个数字。

这里应该算一个bug, 如果伪码长度eax不为0, 并且不比真码
长度大, 而且bstr的内容快也相同的话, 那么也能成功,
实际上是不科学的.
至于eax为什么不能为0, 是因为后面的and eax,eax来判断了.

/*403EDB*/  JE SHORT vb经典编.00403EFF;看到这一行我本来还高兴了一下,以为可以构造一个新的注册码,谁知这条语句跳向的是AND EAX,EAX。希望破灭。
顺便说说这句, 如果是je, 那么一定就是成功了.
在2个串都是机器字长度的倍率的时候, 肯定是je了.
这是属于加速比较串的代码一部分.
2007-2-12 14:15
0
雪    币: 144
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
下个 bp ShowWindow 断他错误提示,然后这个时候翻一下堆栈,就可以发现好马了 不知道这是什么方法...
2007-3-8 17:27
0
游客
登录 | 注册 方可回帖
返回
//