gdb 破解linux程序例子

来源:互联网 发布:java temp目录 编辑:程序博客网 时间:2024/06/10 16:32

摘自: http://www.linuxforum.net/forum/printthread.php?Cat=&Board=cpu&main=534069&type=thread


从网上找滴对我这样的新手帮助很大~~ 

----------------------------------------------------------------------------------------------- 
其实自已也只破解过一个Linux的程序: MTV Player 1.0.6.6, 所以 
这只是个人的一点经验,欢迎大家交流, 我的email是: jesse@263.net 

那就言归正传罗: 

linux的破解(i386)相对于其它unix下的破解自然要容易一些,因为 
大家对于8086系列的结构以及汇编多少都有些了解。不过对于第一次做 
linux下的破解,还是让人感到富有挑战而又令人兴奋的. 
要动手破解,除了破解本身的乐趣外,动力多半还是来自被破解对象 
--应用程序的诱惑, 我就是被mtv player的功能给吸引了,又不满它每次 
只放一小会就静音了, 于是乎我抄起了家伙---gdb 

老实说,原来没怎么用过gdb, 经常是通过xwpe间接的用,于是当时 
就抱了抱佛脚。 
gdb主要是针对源程序的调试除错的,对汇编级的支持的并不好(最 
不好的就是没有类似debug中的a命令,没法汇编),对于破解,gdb常用的命令 
有: 
info target 显示当前目标的一些信息,包括一些分段的信息 
info functions 可以列出所有定义的函数名和数据类型,相当有用, 
有的程序检查系列号和License会在一个名称明确的函数里 
info functions REGEXP 可以列出匹配正规表达表的函数 
info registers 列出所有寄存器(除浮点)的值, 这个跟踪时自然常用到 
info all-registers 列出所有寄存器(包括浮点)的值 
info registers REGNAME... 列出所指出的所有寄存器的值 
info break 列出所有的断点和观察点 
break *ADDR 在地址ADDR处设置断点 
break FUNCTION 在函数FUNCTION处设置断点 
clear FUNCTION 删除在函数FUNCTION入口处的断点 
delete BNUMS 删除BNUMS指定序点的断点或观察点 
backtrace(bt) 显示堆栈中的信息,也很有用,可以在调试中搞清楚当前的调用关系 
x/NFU ADDR 这个也是常用,N:重复数, F:显示格式,s字串,i机器码, 
缺省是x十六进制数, U:单元大小,b字节,h半字(两字节),w字(四字节,缺省) 
ADDR为地址,如 x/3uh 0x54320 
set $REGNAME=VALUE 设定寄存器REGNAME的值为VALUE,还可以是 
set $sp += 4这样的让sp加4 
set {TYPE}ADDR=VALUE 将地址ADDR的TYPE类型的值设为VALUE,例 
如:set {int}0x83040=4 
nexti(ni) 执行一行机器码,如果是函数调用,则执行到函数返回 
stepi(si) 执行一行机器码,如果是函数调用,则进入函数 
disassemble FUNCTION 反汇编FUNCTION函数 
disassemble ADDR1 ADDR2 反汇编ADDR1和ADDR2间的机器码 
disassemble ADDR 反汇编ADDR所在的函数 
run(r) 开始执行程序到第一个断点或程序结束 
continue(c) 继续程序的执行到下一断点或程序结束 
continue(c) IGNORE-COUNT 继续程序的执行并忽略掉IGNORE-COUNT个断 
点,在第IGNORE-COUNT+1个断点停下或程序结束 


正式开工了: 

运行mtv,首先出现的是对话框,要求"Enter Key"或是"Try it!",选"Enter Key", 
填写了资料后,提示注册信息不正确, 显然这其中做了Key的合法性检查,于时选中这 
里做突破口: 

$ gdb mtv 
GNU gdb 4.17 
Copyright 1998 Free Software Foundation, Inc. 
GDB is free software, covered by the GNU General Public License, and you are 
welcome to change it and/or distribute copies of it under certain 
conditions. 
Type "show copying" to see the conditions. 
There is absolutely no warranty for GDB. Type "show warranty" for details. 
This GDB was configured as "i386-redhat-linux"... 
(no debugging symbols found)... 
(gdb) 

通常第一个断点可以设在_start函数处,也可以先运行,中途送中断信号让它停下来 
(一般可以 kill -18 pid, 18是SIGCONT)做这些之前还可以先看看程序中的函数 
(包括使用到的共享库的函数),特别对于Xwindows应用程序,这点十分重要: 
(gdb)info functions 
All defined functions: 

Non-debugging symbols: 
08049cf0 _init 
08049d34 fl_set_object_lstyle 
08049d44 fl_set_object_gravity 
08049d54 fl_add_browser 
08049d64 waitpid 
08049d74 printf 
08049d84 __strtod_internal 
08049d94 fl_set_slider_bounds 
08049da4 fl_set_form_atclose 
08049db4 ungetc 
08049dc4 sigemptyset 
08049dd4 strerror 
08049de4 fl_end_group 
08049df4 hsearch 
08049e04 fl_show_question 
08049e14 fl_add_roundbutton 
08049e24 XCloseDisplay 
08049e34 getenv 
08049e44 fl_add_text 
08049e54 fl_set_input_filter 
08049fd4 fl_hide_object 
08049fe4 lseek 
08049ff4 abort 
0804a004 fl_end_form 
0804a014 fl_remove_io_callback 
0804a024 pipe 
0804a034 fl_set_object_color 
0804a044 fl_set_object_posthandler 
0804a054 calloc 
0804a064 fl_bgn_form 
0804a074 rindex 
0804a084 write 
0804a094 fprintf 
0804a0a4 kill 
0804a0b4 ctime 
0804a0c4 fl_get_menu 
0804a0d4 strcat 
0804a0e4 fl_bgn_group 
0804a0f4 fl_set_atclose 
0804a104 chdir 
0804a114 fl_invalidate_fselector_cache 
0804a124 XCreateBitmapFromData 
0804a134 fseek 
0804a144 mktime 
0804a154 fl_show_fselector 
0804a164 __libc_init_first 
0804a174 fl_do_forms 
0804a184 signal 
0804a194 read 
0804a1a4 fl_get_fselector_form 
0804a1b4 fl_set_form_icon 
0804a1c4 fl_set_slider_value 
0804a1d4 fl_set_timer 
0804a1e4 XParseGeometry 
0804a1f4 fl_show_object 
0804a204 strncpy 
0804a214 unlink 
0804a224 strcasecmp 
0804a234 fl_set_form_geometry 
0804a244 fl_get_menu_item_mode 
0804a254 fl_add_input 
0804a264 fl_get_input <------------------好显眼啊..:P 
0804a274 _IO_getc 
0804a284 fork 
0804a294 sscanf 
0804a2a4 fl_hide_oneliner 
0804a2b4 sigaction 
0804a2c4 fl_set_focus_object 
0804a2d4 strdup 
0804a2e4 gettimeofday 
0804a2f4 fl_add_slider 
0804a304 fopen 
0804a314 memset 
0804a324 ftell 
0804a334 fl_set_menu 
0804a344 fl_get_pattern 
0804a354 fl_set_oneliner_color 
0804a364 fclose 
0804a374 time 
0804a384 fl_add_valslider 
0804a394 fl_set_object_lcol 
0804a3a4 fl_set_object_label 
0804a3b4 fl_set_counter_step 
0804a3c4 fl_library_version 
0804a3d4 fl_show_oneliner 
0804a3e4 sprintf 
0804a3f4 fl_set_border_width 
0804a404 atexit 
0804a414 fl_mapcolor 
0804a424 fl_initialize 
0804a434 fl_set_menu_item_mode 
0804a444 fl_set_input_maxchars 
0804a454 fl_set_browser_fontstyle 
0804a464 fl_get_button 
0804a474 fl_hide_form 
0804a484 fl_set_counter_bounds 
0804a494 fl_set_object_lsize 
0804a4a4 fl_add_checkbutton 
0804a4b4 fl_set_object_callback 
0804a4c4 fl_add_menu 
0804a4d4 fl_use_fselector 
0804a4e4 __errno_location 
0804a4f4 exit 
0804a504 fl_get_filename 
0804a514 __fxstat 
0804a524 fl_add_timer 
0804a534 fl_set_object_resize 
0804a544 open 
0804a554 fl_set_object_lalign 
0804a564 fl_get_directory 
0804a574 fl_show_choice 
0804a584 fl_set_slider_size 
0804a594 fputs 
0804a5a4 execvp 
0804a5b4 fl_get_counter_value 
0804a5c4 close 
0804a5d4 XOpenDisplay 
0804a5e4 free 
0804a604 fl_set_button 
0804a614 _start 
08052e7c whereError 
080583c0 _fini 
mtv用到了xforms库,fl_xxxx都是这个库里的函数, 其中的哪个fl_get_input是 
这么的显眼, 虽然没有做过xforms的编程,但是可以大胆设想这个东东会不会类似 
windows中的GetDlgItemText(GetDlgItemTextA), 所以不妨试试 

(gdb)break fl_get_input 
Breakpoint 1 at 0x804a264 
(gdb)r 
Starting program: /usr/X11R6/bin/mtv 
(no debugging symbols found)...Breakpoint 1 at 0x400429e3 

出现填写注册信息对话框, 我做如下输入 

Name: I007 
Order number: B123456789 (有editmask,只能一字母后跟字数) 
Key: 87654321 (也有editmask) 

按OK键后, mtv果然在断点处停住, 猜得不错. 如果没猜中, 只好慢慢跟踪罗 
(no debugging symbols found)...(no debugging symbols found)... 
Breakpoint 1, 0x400429e3 in fl_get_input () 
(gdb) 

继续让它运行... 
(gdb) c 
Continuing. 

Breakpoint 1, 0x400429e3 in fl_get_input () 
(gdb) c 
Continuing. 

Breakpoint 1, 0x400429e3 in fl_get_input () 
(gdb) c 
Continuing. 

它连续调用了fl_get_input三次, 正好对应三个输入项, 然后注册信息错误的 
对话框就出现了, 看来是没错了, 现在关键是要看最后一次调用fl_get_input 
后的代码,当然看它每次调用fl_get_input后到取回的字串放到了什么地地方 
也很重要.我重新输入一次注册信息,然后让它在三次调用fl_get_input后的 
情况: 
(gdb) c 
Continuing. 

Breakpoint 1, 0x400429e3 in fl_get_input () 
(gdb) bt 
#0 0x400429e3 in fl_get_input () 
#1 0x804ea96 in _start () 
#2 0x4003b5f5 in fl_do_forms () 
#3 0x8050a59 in _start () 

这是堆栈中的情况, 看来调用完fl_get_input后应返回到_start中的 
地址0x804ea96处, 我们来看看这段代码 
(gdb) disass 0x804ea96 0x804ffff 
Dump of assembler code from 0x804ea96 to 0x804ffff: 
0x804ea96 <_start+17538>: movl %eax,0x806e584 
0x804ea9b <_start+17543>: pushl %eax 
0x804ea9c <_start+17544>: movl 0x806e9d4,%eax 
0x804eaa1 <_start+17549>: movl 0x18(%eax),%ecx 
0x804eaa4 <_start+17552>: pushl %ecx 
0x804eaa5 <_start+17553>: call 0x804a264 <fl_get_input> <-第二次 
0x804eaaa <_start+17558>: movl %eax,%ebp 
0x804eaac <_start+17560>: movl 0x806e9d4,%eax 
0x804eab1 <_start+17565>: pushl %eax 
0x804eab2 <_start+17566>: movl 0x10(%eax),%edx 
0x804eab5 <_start+17569>: pushl %edx 
0x804eab6 <_start+17570>: call 0x804a264 <fl_get_input> <-第三次 
0x804eabb <_start+17575>: movl %eax,%ebx 
0x804eabd <_start+17577>: movl %ebp,%edx 
0x804eabf <_start+17579>: movl %ebp,%eax 
0x804eac1 <_start+17581>: addl $0x18,%esp 
0x804eac4 <_start+17584>: andl $0x3,%edx 
0x804eac7 <_start+17587>: je 0x804eadf <_start+17611> 
0x804eac9 <_start+17589>: jp 0x804eada <_start+17606> 
0x804eacb <_start+17591>: cmpl $0x2,%edx 
0x804eace <_start+17594>: je 0x804ead5 <_start+17601> 
0x804ead0 <_start+17596>: cmpb %dh,(%eax) 
.... 
(gdb) break *0x804ea96 
Breakpoint 2 at 0x804ea96 
(gdb) c 
Continuing. 

Breakpoint 2, 0x804ea96 in _start () 
(gdb) info reg eax 
eax 0x8083dd0 134757840 
(gdb) x/s 0x8083dd0 
0x8083dd0: "I007" 

看来 "I007" 放在 0x8083dd0, 这个地址还存放到了 0x806e584 

(gdb) ni 
.... 

到第三次调用fl_get_input完回到0x804eabb时,我们知道了输入的信息存在在哪 

名称 值 地址 
Name "I007" 0x8083dd0 
Order number "B123456789" 0x809e850 
Key "87654321" 0x809e880 

以下的一些反汇编代码中会有一些注释, 主要说明是执行到这样地方时一些情况, 
也不一步步的ni了.. 
(gdb) disass 0x804eabb 0x804ffff 
Dump of assembler code from 0x804eabb to 0x804ffff: 
0x804eabb <_start+17575>: movl %eax,%ebx (eax: 0x809e880->""87654321") 

0x804eabd <_start+17577>: movl %ebp,%edx (ebp: 0x809e850->"B123456789" 

0x804eabf <_start+17579>: movl %ebp,%eax 
0x804eac1 <_start+17581>: addl $0x18,%esp 
0x804eac4 <_start+17584>: andl $0x3,%edx 
0x804eac7 <_start+17587>: je 0x804eadf <_start+17611> -- 
0x804eac9 <_start+17589>: jp 0x804eada <_start+17606> | 
0x804eacb <_start+17591>: cmpl $0x2,%edx | 
0x804eace <_start+17594>: je 0x804ead5 <_start+17601> | 
0x804ead0 <_start+17596>: cmpb %dh,(%eax) | 
0x804ead2 <_start+17598>: je 0x804eb05 <_start+17649> | 
0x804ead4 <_start+17600>: incl %eax | 
0x804ead5 <_start+17601>: cmpb %dh,(%eax) | 
0x804ead7 <_start+17603>: je 0x804eb05 <_start+17649> | 
0x804ead9 <_start+17605>: incl %eax | 
0x804eada <_start+17606>: cmpb %dh,(%eax) | 
0x804eadc <_start+17608>: je 0x804eb05 <_start+17649> | 
0x804eade <_start+17610>: incl %eax | 

以下检查Order number长度是否为10: | 
0x804eadf <_start+17611>: movl (%eax),%edx <- 
0x804eae1 <_start+17613>: testb %dh,%dl 
0x804eae3 <_start+17615>: jne 0x804eaed <_start+17625> 
0x804eae5 <_start+17617>: testb %dl,%dl 
0x804eae7 <_start+17619>: je 0x804eb05 <_start+17649> 
0x804eae9 <_start+17621>: testb %dh,%dh 
0x804eaeb <_start+17623>: je 0x804eb04 <_start+17648> 
0x804eaed <_start+17625>: testl $0xff0000,%edx 
0x804eaf3 <_start+17631>: je 0x804eb03 <_start+17647> 
0x804eaf5 <_start+17633>: addl $0x4,%eax 
0x804eaf8 <_start+17636>: testl $0xff000000,%edx 
0x804eafe <_start+17642>: jne 0x804eadf <_start+17611> 
0x804eb00 <_start+17644>: subl $0x3,%eax 
0x804eb03 <_start+17647>: incl %eax 
0x804eb04 <_start+17648>: incl %eax 
0x804eb05 <_start+17649>: subl %ebp,%eax 
0x804eb07 <_start+17651>: cmpl $0xa,%eax 
0x804eb0a <_start+17654>: jne 0x804ebe6 <_start+17874> 

以下检查Key的长度是否为8: 
0x804eb10 <_start+17660>: movl %ebx,%edx 
0x804eb12 <_start+17662>: movl %ebx,%eax 
0x804eb14 <_start+17664>: andl $0x3,%edx 
0x804eb17 <_start+17667>: je 0x804eb2f <_start+17691> - 
0x804eb19 <_start+17669>: jp 0x804eb2a <_start+17686> | 
0x804eb1b <_start+17671>: cmpl $0x2,%edx | 
0x804eb1e <_start+17674>: je 0x804eb25 <_start+17681> | 
0x804eb20 <_start+17676>: cmpb %dh,(%eax) | 
0x804eb22 <_start+17678>: je 0x804eb55 <_start+17729> | 
0x804eb24 <_start+17680>: incl %eax | 
0x804eb25 <_start+17681>: cmpb %dh,(%eax) | 
0x804eb27 <_start+17683>: je 0x804eb55 <_start+17729> | 
0x804eb29 <_start+17685>: incl %eax | 
0x804eb2a <_start+17686>: cmpb %dh,(%eax) | 
0x804eb2c <_start+17688>: je 0x804eb55 <_start+17729> | 
0x804eb2e <_start+17690>: incl %eax | 
0x804eb2f <_start+17691>: movl (%eax),%edx <- 
0x804eb31 <_start+17693>: testb %dh,%dl 
0x804eb33 <_start+17695>: jne 0x804eb3d <_start+17705> 
0x804eb35 <_start+17697>: testb %dl,%dl 
0x804eb37 <_start+17699>: je 0x804eb55 <_start+17729> 
0x804eb39 <_start+17701>: testb %dh,%dh 
0x804eb3b <_start+17703>: je 0x804eb54 <_start+17728> 
0x804eb3d <_start+17705>: testl $0xff0000,%edx 
0x804eb43 <_start+17711>: je 0x804eb53 <_start+17727> 
0x804eb45 <_start+17713>: addl $0x4,%eax 
0x804eb48 <_start+17716>: testl $0xff000000,%edx 
0x804eb4e <_start+17722>: jne 0x804eb2f <_start+17691> 
0x804eb50 <_start+17724>: subl $0x3,%eax 
0x804eb53 <_start+17727>: incl %eax 
0x804eb53 <_start+17727>: incl %eax 
0x804eb54 <_start+17728>: incl %eax 
0x804eb55 <_start+17729>: subl %ebx,%eax 
0x804eb57 <_start+17731>: cmpl $0x8,%eax 
0x804eb5a <_start+17734>: jne 0x804ebe6 <_start+17874> 

检查Order nuber是否为"I000000000": 
0x804eb60 <_start+17740>: movl %ebp,%esi (ebp:0x809e850->"B123456789 
") 
0x804eb62 <_start+17742>: movl $0x805b9a6,%edi (0x805b9a6->"I000000000 
")0x804eb67 <_start+17747>: movl $0xb,%ecx 
0x804eb6c <_start+17752>: cld 
0x804eb6d <_start+17753>: xorl %eax,%eax 
0x804eb6f <_start+17755>: repz cmpsb %ds:(%esi),%es:(%edi) 
0x804eb71 <_start+17757>: je 0x804eb77 <_start+17763> 


0x804eb73 <_start+17759>: sbbl %eax,%eax 
0x804eb75 <_start+17761>: orb $0x1,%al 
0x804eb77 <_start+17763>: testl %eax,%eax 
0x804eb79 <_start+17765>: jne 0x804ebd1 <_start+17853> - 
... | 
... | 
0x804ebd1 <_start+17853>: pushl %eax (eax:0xffffffff) <- 
0x804ebd2 <_start+17854>: pushl $0x806e9ac (0x806e9ac:0x00000000) 
0x804ebd7 <_start+17859>: pushl %ebx (ebx:0x809e880->"87654321") 
0x804ebd8 <_start+17860>: pushl %ebp (ebp:0x809e850->"B123456789") 
0x804ebd9 <_start+17861>: call 0x8055978 <whereError+11004> 
^____这里很可疑 

0x804ebde <_start+17866>: movl %eax,0x806e574 
0x804ebe3 <_start+17871>: addl $0x10,%esp 
0x804ebe6 <_start+17874>: movl 0x806e574,%edx 
0x804ebec <_start+17880>: testl %edx,%edx 
0x804ebee <_start+17882>: je 0x804ec62 <_start+17998> 
... 
0x804ec62 <_start+17998>: movl 0x806e9d4,%eax 
0x804ec67 <_start+18003>: pushl %eax 
0x804ec68 <_start+18004>: movl (%eax),%edx 
0x804ec6a <_start+18006>: pushl %edx 
0x804ec6b <_start+18007>: call 0x804a474 <fl_hide_form> 
0x804ec70 <_start+18012>: pushl $0x1 
0x804ec72 <_start+18014>: pushl $0x8059017 
0x804ec77 <_start+18019>: pushl $0x805ba6c (0x805ba6c->"Check 
registration information and try again") 
0x804ec7c <_start+18024>: pushl $0x805ba99 (0x805ba99->"Incorrect 
registration information!") 
0x804ec81 <_start+18029>: call 0x804a790 <_start+380> (警告框出现) 
....... 

到注册信息不对的警告框出现,只有一个函数调用比较可疑: 
0x804ebd9 call 0x8055978 <whereError+11004> 
而且调用结束后还有一个比较跳转的动作, 那么我们就跟踪进去看看 
(gdb) break *0x8055978 
Breakpoint 3 at 0x8055978 
(gdb) c 
Continuing. 

Breakpoint 3, 0x8055978 in whereError () 
(gdb) disass 0x8055978 0x805ffff 
Dump of assembler code from 0x8055978 to 0x805ffff: 
0x8055978 <whereError+11004>: subl $0x8,%esp 
0x805597b <whereError+11007>: pushl %ebp 
0x805597c <whereError+11008>: pushl %edi 
0x805597d <whereError+11009>: pushl %esi 
0x805597e <whereError+11010>: pushl %ebx 
0x805597f <whereError+11011>: movl 0x1c(%esp,1),%ebp (0x809e850) 
0x8055983 <whereError+11015>: movl 0x20(%esp,1),%esi (0x809e880) 
0x8055987 <whereError+11019>: movl 0x24(%esp,1),%ebx (0x806e9ac) 
0x805598b <whereError+11023>: testb $0x1,(%ebx) 
0x805598e <whereError+11026>: je 0x80559c0 <whereError+11076> - 
..... | 
0x80559c0 <whereError+11076>: pushl %eax < 
0x80559c1 <whereError+11077>: leal 0x18(%esp,1),%eax 
0x80559c5 <whereError+11081>: pushl %eax (eax:0xbffff70c) 
0x80559c6 <whereError+11082>: pushl $0x8060cbb (0x8060cbb->" %x") 
0x80559cb <whereError+11087>: pushl %esi (esi:0x809e880->"87654321") 
0x80559cc <whereError+11088>: call 0x804a294 <sscanf> 
0x80559d1 <whereError+11093>: movl %eax,%edi(此时0xbffff70c->0x87654321) 
0x80559d3 <whereError+11095>: addl $0x10,%esp 
0x80559d6 <whereError+11098>: cmpl $0x1,%edi 
0x80559d9 <whereError+11101>: je 0x8055a01 <whereError+11141> - 
..... | 
0x8055a01 <whereError+11141>: testb $0x1,(%ebx) <- 
0x8055a04 <whereError+11144>: je 0x8055a3a <whereError+11198> - 
..... | 
0x8055a3a <whereError+11198>: pushl %ebp(ebp:0x809e850->"B123456789") <- 
0x8055a3b <whereError+11199>: pushl $0x0 
0x8055a3d <whereError+11201>: call 0x80561d9 <whereError+13149> 
^______会不会去算正确的Key? 

0x8055a42 <whereError+11206>: movl %eax,%esi (eax:0x8eee5816) 
0x8055a44 <whereError+11208>: addl $0x8,%esp 
0x8055a47 <whereError+11211>: testb $0x1,(%ebx) 
0x8055a4a <whereError+11214>: je 0x8055a7a <whereError+11262> - 
..... | 
0x8055a7a <whereError+11262>: movl 0x14(%esp,1),%edx <- 
0x8055a7e <whereError+11266>: cmpl %esi,%edx 
(edx:0x87654321,这是我输入的Key 
它在与0x8eee5816比较???) 
0x8055a80 <whereError+11268>: jne 0x8055ab9 <whereError+11325> - 
.... | 
0x8055ab9 <whereError+11325>: testb $0x1,(%ebx) <- 
0x8055abc <whereError+11328>: je 0x8055aec <whereError+11376> - 
.... | 
0x8055aec <whereError+11376>: xorl %eax,%eax <- 
0x8055aee <whereError+11378>: popl %ebx 
0x8055aef <whereError+11379>: popl %esi 
0x8055af0 <whereError+11380>: popl %edi 
0x8055af1 <whereError+11381>: popl %ebp 
0x8055af2 <whereError+11382>: addl $0x8,%esp 
0x8055af5 <whereError+11385>: ret 

0x8055a7e处的比较说明, 很有可能函数0x80561d9就是在依照我输入的Order 
number算正确的Key,而后比较结果,所以不妨先用 8EEE5816 做Key试一试. 

结果,8EEE5816果然就是正确的Key, mtv检查正确后在$HOME目录中产生一个 
.mtvrc文件, 以后每次使用都会自动读出.mtvrc中的注册信息并检查.. 

还可以据0x80561d9函数写出注册机: 

(gdb) disass 0x80561d9 0x805624e 
Dump of assembler code from 0x80561d9 to 0x805624e: 
0x80561d9 <whereError+13149>: pushl %edi 
0x80561da <whereError+13150>: pushl %esi 
0x80561db <whereError+13151>: pushl %ebx 
0x80561dc <whereError+13152>: movl 0x14(%esp,1),%edi 
0x80561e0 <whereError+13156>: movl 0x10(%esp,1),%edx 
0x80561e4 <whereError+13160>: xorl %ebx,%ebx 
0x80561e6 <whereError+13162>: movl %edi,%eax 
0x80561e8 <whereError+13164>: movl %edi,%esi 
0x80561ea <whereError+13166>: andl $0x3,%eax 
0x80561ed <whereError+13169>: je 0x8056205 <whereError+13193> 
0x80561ef <whereError+13171>: jp 0x8056200 <whereError+13188> 
0x80561f1 <whereError+13173>: cmpl $0x2,%eax 
0x80561f4 <whereError+13176>: je 0x80561fb <whereError+13183> 
0x80561f6 <whereError+13178>: cmpb %ah,(%esi) 
0x80561f8 <whereError+13180>: je 0x8056229 <whereError+13229> 
0x80561fa <whereError+13182>: incl %esi 
0x80561fb <whereError+13183>: cmpb %ah,(%esi) 
0x80561fd <whereError+13185>: je 0x8056229 <whereError+13229> 
0x80561ff <whereError+13187>: incl %esi 
0x8056200 <whereError+13188>: cmpb %ah,(%esi) 
0x8056202 <whereError+13190>: je 0x8056229 <whereError+13229> 
0x8056204 <whereError+13192>: incl %esi 
0x8056205 <whereError+13193>: movl (%esi),%eax 
0x8056207 <whereError+13195>: testb %ah,%al 
0x8056209 <whereError+13197>: jne 0x8056213 <whereError+13207> 
0x805620b <whereError+13199>: testb %al,%al 
0x805620d <whereError+13201>: je 0x8056229 <whereError+13229> 
0x805620f <whereError+13203>: testb %ah,%ah 
0x8056211 <whereError+13205>: je 0x8056228 <whereError+13228> 
0x8056213 <whereError+13207>: testl $0xff0000,%eax 
0x8056218 <whereError+13212>: je 0x8056227 <whereError+13227> 
0x805621a <whereError+13214>: addl $0x4,%esi 
0x805621d <whereError+13217>: testl $0xff000000,%eax 
0x8056222 <whereError+13222>: jne 0x8056205 <whereError+13193> 
0x8056224 <whereError+13224>: subl $0x3,%esi 
0x8056227 <whereError+13227>: incl %esi 
0x8056228 <whereError+13228>: incl %esi 
0x8056229 <whereError+13229>: subl %edi,%esi 
0x805622b <whereError+13231>: cmpl %esi,%ebx 
0x805622d <whereError+13233>: jnl 0x8056248 <whereError+13260> 
0x805622f <whereError+13235>: movb (%ebx,%edi,1),%al 
0x8056232 <whereError+13238>: incl %ebx 
0x8056233 <whereError+13239>: andl $0xff,%eax 
0x8056238 <whereError+13244>: pushl %eax 
0x8056239 <whereError+13245>: pushl %edx 
0x805623a <whereError+13246>: call 0x8055b58 <whereError+11484> 
0x805623f <whereError+13251>: movl %eax,%edx 
0x8056241 <whereError+13253>: addl $0x8,%esp 
0x8056244 <whereError+13256>: cmpl %esi,%ebx 
0x8056246 <whereError+13258>: jl 0x805622f <whereError+13235> 
0x8056248 <whereError+13260>: popl %ebx 
0x8056249 <whereError+13261>: movl %edx,%eax 
0x805624b <whereError+13263>: popl %esi 
0x805624c <whereError+13264>: popl %edi 
0x805624d <whereError+13265>: ret 

0x8055b58处的函数太长了, bbs不让我发..:( 砍掉了 

由这个程序的破解可以看出, linux下的破解并不困难, 只是gdb有点不太方便 
有时会有点小毛病(比如ni有时也会跟到函数中), 不过用多了就习惯了.