软编码寻找序列号(一)
使用工具
- OllyDbg 1.10原版,简称
OD
; OD
汉化
和插件
均来自互联网;- CrackMe来自互联网,仅供学习使用;
- 文中特殊数字均是
HEX
,为了书写方便采用DEC
;
逆向思路
首先,打开软件到处点点,逆向一个软件起码要会用吧,不会用就没必要说逆向了:
倒入
OD
开始分析:首先按下
Ctrl + A
让OD
分析一下代码;接着按下
Ctrl + N
查看使用了哪些API
,用的API
不多,一眼就看到了GetDlgItemTextA
,在GetDlgItemTextA
函数上设置断点,然后去断点窗口
双击断点进入反汇编窗口
给断点设置备注,这是一个好的习惯,请保持;然后
F9
运行程序,输入用户名和注册码,点击确定;程序断下来了,在堆栈窗口选择
Buffer
右键数据窗口中跟随
,没有数据,因为断点在行首,Ctrl + F9
或者点击菜单栏调试选项,选择执行到返回
,再去数据窗口中看看,有数据了,是我们输入的用户名;再次运行程序,程序再次中断,不出意外应该是获取注册码,在堆栈窗口选择
Buffer
右键数据窗口中跟随
,没有数据,Ctrl + F9
或者点击菜单栏调试选项,选择执行到返回
,再去数据窗口中看看,有数据了,是我们输入的注册码;能获取到数据就是一个好的开始,
F7 或 F8
单步执行到程序领空,熟悉的字样映入眼帘:
既有我们输入的内容,也有提示字样,应该就是这里了,那就开始分析;前面的代码是堆栈平衡和清除弹窗的代码,进
CALL
之后,直接ALT + F9
或者点击菜单栏调试选项,选择执行到用户代码
;需要分析的代码来了:刚分析了两行,发现了几行特别的代码:
这几行代码,一个
push
然后紧跟着一个CALL
,而且 push 的是我们输入的内容,这里应该就是关键了;F7
进第 1 个CALL
看看:刚进来第 1 行代码有困惑的吗?你咋知道是用户名放入
ESI 寄存器
?很简单,
[ESP+4]
告诉我的,ESP 寄存器
永远指向堆栈的顶端,那[ESP+4]
就是下一行喽,看一眼堆栈窗口,第二行的数据不正是我们输入的用户名吗?接着,出现了第 2 处令人疑惑的代码:
机器码和
41
比较,这到底是啥意思?刚开始我也弄不明白,而且后面的逻辑也显示和41
半毛钱关系没有,直到无意中在用户名输入了数字,弹出两次注册失败
,才好像明白了这里判断的是啥?我们先看看 16 进制的41
到底是什么:原来
41
是大写字母A
,而后面的5A
则是大写字母Z
,那我好像明白怎么回事儿了,它应该是在判断用户名是否是英文字母;当字符的机器码大于
41
并且大于5A
时,程序会跳转到一个新的CALL
,那它干了什么呢:可以看到,这里只有 3 行代码,我们分析一下,小写字母的机器码减去
20
是什么,没错,是对应的大写字母,这三行代码的作用就是:将用户名转换为大写字母,然后用大写字母替换用户名中的小写字母,然后返回:当用户名全部转为大写字母之后,又来到了一个
CALL
,这个CALL
又是干什么的呢,F7
跟进去看看:原来,是将转换为大写字母后的用户名的每个字节的机器码累加在一起,然后和
5678
异或,并把异或后的结果放入EAX
并返回:
用户名处理完了,接下来就是注册码了:
刚从用户名的连环
CALL
里出来就这么刺激吗?把用户名运算后的结果和我们输入的注册码都 push 到了这个CALL
里面,这里应该就是比较了;结果很打脸啊,不是验证
CALL
而是运算注册码的CALL
,而第一行的PUSH EAX
只是个入栈而已。。。验证环节
根据
CALL
跳转的位置,轻松知道它的用途;注册码的计算规则:
- 用户名必须是字母;
- 将每个字母转为大写字母;
- 把每个字母的 16 进制累加在一起;
- 累加的结果与 5678 异或;
- 异或后的结果与 1234 异或;
- 将最后的结果转为 10 进制,注册码就出来啦;
无图无真相
例如:
yang
的大写YANG
的 16 进制是59 41 4E 47
;加在一起是
59 + 41 + 4E + 47 >> 12F
;12F
与5678
异或xor 12F, 5678 >> 5757
;5757
与1234
异或xor 5757, 1234 >> 4563
;4563
转为 10 进制后17763
;