欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

优化爆破修改标志位

程序员文章站 2022-09-19 18:37:19
文/图 Hokkien     很多朋友都想当然的以为爆破很简单,其实不然,想要做到简单且优美的爆破,并不是那么容易的。所以,我们今天就对...
文/图 Hokkien

    很多朋友都想当然的以为爆破很简单,其实不然,想要做到简单且优美的爆破,并不是那么容易的。所以,我们今天就对如何优化爆破进行简单的讨论。
标志位修改是爆破当中技巧性较强的方法。如果能够用好标志位的修改,将会使软件爆破的复杂性大大降低,因而,我们有理由认为,标志位的修改与否,将是一个软件是否完美爆破的关键。
在谈到标志位的实现,大家不妨先看看下面的一个例子。

BOOL IsReg() //验证是否注册的函数
{  
……
if(RegFlag==Ture) // RegFlag是注册标志
return Ture;
else
return False;
}
void Function1() //软件功能1
{
if(IsReg())
{
……
}
else
{
printf(“对不起,你还未注册,不能使用本功能1!”);
return;
}
}
void Function2()    //软件功能2
{
if(IsReg())
{
……
}
else
{
printf(“对不起,你还未注册,不能使用本功能2!”);
return;
}
}
上面虽然是一个很简单的验证方法,但却是很多软件验证中的一道工序。对于类似的验证流程,一般的爆破改法是,在Function1()和Function2()内部的比较跳转中分别改JNE为JE。这样的改法虽然可行,但有一个很明显的缺点,那就是修改太多处,这是爆破的大忌。试想一下,如果软件中大量调用IsReg函数进行注册判断,那这种改法所耗的时间就不难想象了。因而,我们有必要寻找一种更简便的方法,能让我们以最少的时间,最小的修改达到同样的目的。这种方法就是修改标志位。为了更清楚的理解,大家不妨观察一下上面的代码。在上面的代码中,Function1和Function2对于是否实现本功能是根据IsReg是否为真这个条件决定的。现在我们换另一种思维思考,如果不管如何,IsReg都返回为真,那是不是Function1和Function2就能实现自身的功能呢?答案是肯定的。因而,我们可以找到IsReg这段代码,把返回值直接修改为真,也就是对返回值直接赋值为真,那么,软件便会照着预想的流程运行,这就是标志位的修改。为了大家更好的掌握这种方法,下面举两个很典型的例子。
          
修改标志位完美爆破Ultra MP3 to CD Burner v1.6.0
Ultra MP3 to CD Burner v1.6.0是一款功能强大操作简单的刻录软件,支持MP3、WAV、WMA、OGG等音频格式,整体感觉还是挺不错的。但它是一款共享软件,有时间限制,而且软件一启动,就会跳出一个提示注册的窗口,如图1所示。
优化爆破修改标志位
            图1
   现在我们就来破解它。首先查壳,显示“Microsoft Visual C++ 6.0”编译。看来作者对自己的算法很自信呀,竟然没有加壳。好,用OD载入软件,忽略几个异常后,程序停在入口处。查找字符串参考,找到“invalid user name or register code”,双击来到相应代码处。

    0040EA92 .  E8 99F9FFFF CALL Ultra_MP.0040E430
0040EA97 .  83C4 08  ADD ESP,8
0040EA9A .  85C0  TEST EAX,EAX
0040EA9C  75 2B  JNZ SHORT Ultra_MP.0040EAC9
0040EA9E .  6A 40  PUSH 40
0040EAA0 .  68 E49D4100 PUSH Ultra_MP.00419DE4;sorry
0040EAA5 .  68 C09D4100 PUSH Ultra_MP.00419DC0
;invalid user name or register code
  
我们选择在0040EA92处下断点,F9运行软件,在注册框中输入用户名“Hokkien”,注册码输入“12345abcde”,点确定后,程序被断在相应处。F7步入0040EA92,来到下面代码处。

0040E430  /$  6A FF  PUSH -1
0040E432 68D9384100 PUSH Ultra_MP.004138D9
;SE处理程序安装
0040E437  |.  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
0040E43D  |.  50  PUSH EAX
0040E43E  |.  64:8925 00000>MOV DWORD PTR FS:[0],ESP
0040E445  |.  81EC 94000000 SUB ESP,94
0040E44B  |.  8B8424 A40000>MOV EAX,DWORD PTR SS:[ESP+A4]
0040E452  |.  53  PUSH EBX
0040E453  |.  56  PUSH ESI
0040E454  |.  50  PUSH EAX
0040E455  |.  8D4C24 10   LEA ECX,DWORD PTR SS:[ESP+10]
0040E459  |.  C74424 60 E1B>MOV DWORD PTR SS:[ESP+60],6547BCE1
0040E461  |.  C74424 64 133>MOV DWORD PTR SS:[ESP+64],C43F3613
0040E469  |.  C74424 68 CF1>MOV DWORD PTR SS:[ESP+68],2EFD1DCF
0040E471  |.  C74424 6C C56>MOV DWORD PTR SS:[ESP+6C],1D286CC5
0040E479  |.  C74424 70 7F7>MOV DWORD PTR SS:[ESP+70],1DB07B7F
0040E481  |.  C74424 74 016>MOV DWORD PTR SS:[ESP+74],775F6901
0040E489  |.  C74424 78 B94>MOV DWORD PTR SS:[ESP+78],5BEC44B9
0040E491  |.  C74424 7C 38D>MOV DWORD PTR SS:[ESP+7C],3637D938

哇,这么多数字!看来,算法确实很复杂!不过我们不用管它,因为我们的目的是爆破。但在爆破之前,不要着急,不妨把OD上下的代码粗略看看,这样有助于发现爆破点。继续往下翻代码,来到这里。

0040EA92 .  E8 99F9FFFF call  0040E430
0040EA97 .  83C4 08  add   esp, 8
0040EA9A .  85C0  test  eax, eax
0040EA9C .  75 2B  jnz   short 0040EAC9;关键跳转
0040EA9E .  6A 40  push  40
0040EAA0 .  68 E49D4100 push  00419DE4; ASCII "Sorry"
0040EAA5 .  68 C09D4100 push  00419DC0
; ASCII "Invalid user name or register code"

看到这段代码,我们心里有数了,上面不就是关键跳吗?那能不能修改这个关键跳就爆破成功呢?实践表明,这样是不会成功的,有兴趣的朋友可以试下,这里就不再废话了。那是不是爆破不了了呢?回答这个问题之前,让我们先分析一下上面这段代码。

0040EA9A .  85C0  test  eax, eax
0040EA9C .  75 2B  jnz   short 0040EAC9

这2行代码对EAX进行测试,如果等于0的话则注册失败。很明显,上面应该有个CALL。那么,这个CALL就相当于C语言中声明的BOOL型,如果注册为真返回TRUE,否则返回FAULSE。所以,爆破的关键是,查找上面CALL的对EAX赋值的代码,然后进行修改。好了,按照这个思路,我们进入上面那个CALL看看,来到下面的代码处。

0040E696  |.  85C0  test  eax, eax
0040E698  |.  C68424 A40000>mov   byte ptr [esp+A4], 6
0040E6A0  0F84 86000000 je  0040E72C;关键跳转!
0040E6A6  |.  E8 0F350000 call  <jmp.&MFC42.#800>
0040E6AB  |.  8D4C24 4C   lea   ecx, dword ptr [esp+4C]
0040E6AF  |.  C68424 A40000>mov   byte ptr [esp+A4], 5
0040E6B7  |.  E8 E4260000 call  00410DA0
0040E6BC  |.  8D4C24 34   lea   ecx, dword ptr [esp+34]
0040E6C0  |.  889C24 A40000>mov   byte ptr [esp+A4], bl
0040E6C7  |.  E8 D4260000 call  00410DA0
0040E6CC  |.  8D4C24 44   lea   ecx, dword ptr [esp+44]
0040E6D0  |.  C68424 A40000>mov   byte ptr [esp+A4], 8
0040E6D8  |.  E8 C3260000 call  00410DA0
0040E6DD  |.  8D4C24 3C   lea   ecx, dword ptr [esp+3C]
0040E6E1  |.  C68424 A40000>mov   byte ptr [esp+A4], 1
0040E6E9  |.  E8 B2260000 call  00410DA0
0040E6EE  |>  8D4C24 08   lea   ecx, dword ptr [esp+8]
0040E6F2  |.  C68424 A40000>mov   byte ptr [esp+A4], 0
0040E6FA  |.  E8 BB340000 call  <jmp.&MFC42.#800>
0040E6FF  |.  8D4C24 0C   lea &nb