信息收集

1、程序是一个32位程序,并且没有壳,并且是用Delphi 6.0编写的。 image-20230426202100123.png 2、存在的一些提示字符:“请重启软件验证注册码”、“未注册”这些。 image-20230426202333559.png 3、程序会生成一个dll文件,文件中记录了输入的用户名和密码。 image-20230426202442057.png image-20230426202524733.png 通过这些我们可以推测,这个程序会生成一个带有注册码的dll文件,然后在启动程序的时候会读取文件的内容用于验证是否注册。

分析

1、通过提示字符可以帮助我们快速定位到程序的核心代码处。 image-20230426210527727.png 重启应该就是注册码错误,而告诉有效期则代表注册成功,所以直接跳转到有效期处的代码,然后观察下断。 image-20230426210934333.png 并没有跳转,也没调用窗口,所以这应该和未注册一样是显示在程序上的。 image-20230426211120223.png 我下了两个断点,第一个在有效期处,第二个在注册失败处。image-20230426211403703.pngimage-20230426211438533.png

动态分析

程序先运行到有效期处,通过数据跟随可以知道Reg.0045D5C0就是这个字符串。 image-20230426211714221.png 先不进入Reg.004043F8这个函数,通过观察堆栈和寄存器的反应可以知道,它将字符串给到了local.1处。 image-20230426212210200.png image-20230426212227932.png 这里需要注意的是在获取完Reg.dll之后马上执行了Reg.004088D4函数并跟着一个test比较,这里是第一个跳转,并且还没有读取到用户名和注册码,猜想这里应该是验证reg.dll文件是否存在。删除了reg.dll后重新跳转到该处单步执行,就直接跳转了。(一般的正向逻辑也是先验证文件是否存在,存在再开始读取文件内容) image-20230426212952174.png image-20230426213013231.png 果然在执行完一遍,它生成了一个reg.dll之后它再运行到该函数的位置就不会跳转了。接着往后看就会发现有读取reg.dll文件的操作了。image-20230426215242436.png image-20230426215301231.png edx原本存储的是username,执行了该函数后就变成了username=用户名,所以可以知道的是该函数从dll文件中读取到用户名并将它先存入栈中,然后将用户名和edx中的username进行一个拼接操作。同理后面的序列号也是同样的操作。 image-20230426215806401.png 执行到上面这个地方的时候就开始警惕了,因为它将用户名和序列号都作为参数开始传入函数Reg.0045D0F4中并且后面就是一个跳转。 image-20230426220109162.png 运行下去的话就直接跳转了,修改一下,看看不跳转的执行内容。 image-20230426220252552.png 这不就是我们想要的吗。这下就结束了,目的达到!下班!!! 进入函数查看,直接运行到后面,这里的函数就用到了我们输入的用户名和一个日期作为参数,并将生成的结果放在[ebp-0x10],这很有可能就是注册码。 image-20230426221116008.png 得到结果 :ASCII "E7345653A6844550"。试一下: image-20230426223921492.png 总结:先找到关键的判断跳转点,之后再进入算法函数得到注册码,先看能不能直接得到注册码,如果不能再一步一步分析算法实现。