首页
社区
课程
招聘
[原创]dpxdp的16Bit DOS crackme分析
2007-6-11 20:36 7437

[原创]dpxdp的16Bit DOS crackme分析

2007-6-11 20:36
7437
【破文标题】dpxdp的16Bit DOS crackme分析
【对  象】初入门的新手
【下载地址】 crackme.rar
【破解工具】TD,IDA
【保护方式】序号
【破文作者】不懂算法
【破解声明】我很菜,写这篇东西是给刚入门的兄弟,高手请飘过
【备  注】老手勿看,别浪费你的时间
【电  邮】[EMAIL="wzlei0409@gmail.com"]wzlei0409@gmail.com[/EMAIL]
【破解过程】
    16Bit的DOS程序是很邪恶的,对于我们这些习惯用OD的人简直是恶梦。
    首先我尝试用IDA加载,然后试遍了所有签名,没有一个是合适的,这样IDA分析的结果几乎不能看了。
    我向该crackme作者询问这个程序是由那个编译器编译的,作者就是不肯透露,邪恶的人呀。
    于是就翻出了TD(Turbo Debugger for DOS),以前没有用过,这次就当时学习了,Luck的是TD跟OD的很多调试快捷键是一样的,或者说OD作者参考了TD吧。
    一般来说,每个编译器都会在用户编写的main函数前面加上一大堆初始化代码,主要对一些环境进行判断和初始化操作。
    我们先用用F8单步步过,当发现跳过关键CALL的时候(用Alt+F5可以看用户窗口是否提示输入,或者打印出Sorry or Good),这个CALL结束后光标停在CALL的下一条代码,我们要想进入这个CALL,就把光标移CALL的地方,按F2下断点,然后按Ctrl+F2重新加载程序,再按F9就断在刚才那个关键CALL了,这时候按F2清除断点,按F7跟进这个CALL,然后在这个CALL里面在找关键CALL,以此类推。
    其实TD也有内存访问断点和硬件断点的,不过我却用不了,提示我说我的机器硬件不支持,汗一个,我估计可能是由于我在window2003下,不是真实的DOS环境造成的吧。
    总之,于是乎,不管怎么说吧,我们还是找到了关键CALL。
我在IDA里面找到这个CALL,根据我们用TD动态分析的结果,我们大概知道下面每个CALL的作用,我们再来分析一下下面这段代码,其实是连蒙带猜的。
seg000:0001 main proc far ; CODE XREF: _main+D P
seg000:0001
seg000:0001 var_4 = word ptr -4
seg000:0001 var_2 = word ptr -2
seg000:0001
seg000:0001 push bp
seg000:0002 mov bp, sp
seg000:0004 sub sp, 4
seg000:0008 push di
seg000:0009 push si
seg000:000A xor ax, ax
seg000:000C push ax
seg000:000D push ax
seg000:000E call sub_12886        要往屏幕打印信息的初始化
seg000:000E
seg000:0013 mov ax, 2Bh ; '+' ; <suspicious> 要打印的字符个数
seg000:0016 push ax
seg000:0017 mov ax, 9AAh ; <suspicious> 其实就是字符串”Please input serial 
                                                    number (no character) :”的地址
seg000:001A push ds
seg000:001B push ax
seg000:001C call sub_12C38            开始打印字符串
seg000:001C
seg000:0021 call sub_127B7            打印结束
seg000:0021
seg000:0026 xor ax, ax
seg000:0028 push ax
seg000:0029
seg000:0029 loc_10029:
seg000:0029 mov ax, 1
seg000:002C push ax
seg000:002D mov ax, 7FFFh
seg000:0030 push ax
seg000:0031 mov ax, 64h ; 'd' ; <suspicious> 是字符串(I9,I2)
seg000:0034 push ds
seg000:0035 push ax
seg000:0036 call sub_11FB8            初始化接收输入
seg000:0036
seg000:003B mov ax, 5Ch ; '\' ; <suspicious>
seg000:003E push ds
seg000:003F push ax
seg000:0040 call sub_125C5            把I9得到的数值放在ds:[5C]里面
seg000:0040
seg000:0045 mov ax, 60h ; '`' ; <suspicious>
seg000:0048 push ds
seg000:0049 push ax
seg000:004A call sub_125C5            把I2得到的数值放在ds:[60]里面
seg000:004A
seg000:004F call sub_120B3            接收输入结束
                                    我们看上面这个接收输入的函数是靠(I9,I2)做为格式的
                                    说明取输入的前9个数字字符,转换为一个DWORD数值
                                    从9个后面取2个数字字符,再转换成一个DWORD数值
                                    我接触的语言比较少,不知道那位大侠知道什么语言是靠
                                    这样的格式接收数值的,就可以知道作者用什么编程语言
seg000:004F
seg000:0054 push word ptr ds:62h    DOS下每次push只能push一个WORD
seg000:0058 push word ptr ds:60h    所以一个数值要push两次
seg000:005C mov ax, 3            3次方的意思
seg000:005F xor dx, dx
seg000:0061 push dx
seg000:0062 push ax
seg000:0063 call sub_11531        这个是乘方函数,结果放在ax,dx里面
seg000:0063
seg000:0068 push word ptr ds:62h
seg000:006C push word ptr ds:60h
seg000:0070 mov [bp+var_4], ax    把ds:[60]的3次方保存在局部变量里面
seg000:0073 mov [bp+var_2], dx
seg000:0076 mov ax, 2            2次方
seg000:0079 xor dx, dx
seg000:007B push dx
seg000:007C push ax
seg000:007D call sub_11531        还是那个乘方函数
seg000:007D
seg000:0082 add ax, [bp+var_4]    
seg000:0085 adc dx, [bp+var_2]    这两个操作是2次方加上保存的3次方
seg000:0088 add ax, ds:60h        
seg000:008C adc dx, ds:62h        再加上本身,就是1次方
seg000:0090 mov ds:6Ch, ax
seg000:0093 mov ds:6Eh, dx        把3次方,2次方,1次方的和放在ds:[6C]
seg000:0097 mov ax, ds:5Ch
seg000:009A mov dx, ds:5Eh        取出[5C]的数值,就是我们输入的9位数
seg000:009E sub ax, ds:6Ch
seg000:00A2 sbb dx, ds:6Eh        减去[6C]也就是刚才的运算结果
seg000:00A6 or ax, dx            或操作,说明要求ax,dx都是0,ax才是0
seg000:00A8 jnz short loc_100C8    不等0就跳
seg000:00A8
seg000:00AA xor ax, ax
seg000:00AC push ax
seg000:00AD push ax
seg000:00AE call sub_12886        上面分析过了,打印字符初始化
seg000:00AE
seg000:00B3 mov ax, 5            5个字符
seg000:00B6 push ax        
seg000:00B7 mov ax, 9D5h ; <suspicious>            “Good!”
seg000:00BA push ds
seg000:00BB push ax
seg000:00BC call sub_12C38        打印到屏幕
seg000:00BC
seg000:00C1 call sub_127B7        打印结束
seg000:00C1
seg000:00C6 jmp short loc_100E4
seg000:00C6
seg000:00C8 ; ---------------------------------------------------------------------------
seg000:00C8
seg000:00C8 loc_100C8: ; CODE XREF: main+A7 j
seg000:00C8 xor ax, ax
seg000:00CA push ax
seg000:00CB push ax
seg000:00CC call sub_12886        打印初始化
seg000:00CC
seg000:00D1 mov ax, 6            6个字符
seg000:00D4 push ax
seg000:00D5 mov ax, 9DAh ; <suspicious>        “Sorry!”
seg000:00D8 push ds
seg000:00D9 push ax
seg000:00DA call sub_12C38        开始打印到屏幕
seg000:00DA
seg000:00DF call sub_127B7        结束打印
seg000:00DF
seg000:00E4
seg000:00E4 loc_100E4: ; CODE XREF: main+C5 j
seg000:00E4 pop si
seg000:00E5 pop di
seg000:00E6 mov sp, bp
seg000:00E8 pop bp
seg000:00E9 retf
seg000:00E9
seg000:00E9 main endp

【总结】
    经过上面的分析我们知道,该crackme接收用户输入的前9个字符转化为数值Y,接收第10和第11个字符转化为数值X,然后比较Y是否等于X的三次方+二次方+X,如果相等就输出“Good!”,不等就输出”Sorry”。
    一个简单算法的crackme,不过由于是16Bit的DOS程序,而且是不知道什么编译器编译的程序,分析起来会花费相当的时间。
给出注册机
main()
{
    int rd;
    srand((unsigned int)time(0));
    rd=rand()%100;
    printf("serial number is: %09d%02d\n",rd*rd*rd+rd*rd+rd,rd);
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
打赏
分享
最新回复 (6)
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
yingyue 2007-6-11 23:09
2
0
不错,学习了,很懂算法是我的偶像已经是很明显的
雪    币: 202
活跃值: (77)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
不懂算法 2 2007-6-11 23:20
3
0
你的发帖量已经超过我那么多了
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
yingyue 2007-6-12 00:18
4
0
菜鸟就只好灌水了
雪    币: 241
活跃值: (35)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
haoshuaioo 1 2007-6-12 04:06
5
0
我也灌一个。
雪    币: 244
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
yaleond 1 2007-6-14 19:38
6
0
狂晕...楼主厉害
-
-
十分支持你!!!

看到那个DOS的,用OD不能调试我就没去做过多考虑,直接放弃...还是太菜...
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
linklimit 2007-6-17 15:42
7
0
dos下程序以前没弄过,学习了。
游客
登录 | 注册 方可回帖
返回