网络验证保护的程序也是比较流行的,把验证客户端程序的数据放在服务器上与客户端进行交互比对。
这个小程序分客户端和服务端,正常情况下我们只能了解客户端,将客户端程序CrackMeNet.exe拖入IDA中进行分析,通过导入表函数我们可以知道是通过send()和dev()套接层链接函数进行网络验证的。
两个函数原型:
int send(
SOCKET s, //套接字描述符
const char FAR *buf, //缓冲区
int len, //实际要发送的数据的字节数
int flags //附加标志,一般为0
);
int recv(
SOCKET s, //套接字描述符
const char FAR *buf, //缓冲区
int len, //实际要发送的数据的字节数
int flags //附加标志,一般为0
);
通过交叉引用(Ctrl+x),来到调用这两个函数的位置知道,我们输入的数据是经过异或加密和解密的。
这个时候我们修改这个程序的思路就是,将封包中的数据整合到一起,客户端与服务端交互的两个函数send和recv去除,send函数数据加密是在函数前,而recv数据解密是在后,所以将函数去除之后,我们只要在recv函数地址处跳过后面的解密段,而send函数的修改参考recv函数接收数据后的代码读取位置。
分析一下recv函数以及它的解密代码:
网络连接的接收函数recv获取数据后将它从eax转移到参数var_28C处,即 [ebp+var_28C] ,参数var_238作为它循环解密的计数器,初始值为0;
所以ebp这个寄存器上放有我们的接收到的待解密数据,在004016A6处,将待解密数据转移到edx寄存器的低位地址dl里;
再将它与6Eh进行异或(xor)解密。将解密后的数据放入 [eax+41AE68] 这个地址处;
计数器 [ebp+var_238] 数值增加,解密下一位置,直到将加密数据解密完,跳转出去(地址0040169C:jge short loc_4016BE)。
所以在修改接收函数recv时在我们函数recv()的第一个参数位置00401655处,将push指令修改为jmp short 004016BE (这里代码位置均为0040x16**,所以是段内短转移),直接跳转到完成解密之后跳转的位置。
在修改代码之前,我们需要先确认解密后数据存放的位置长度,也就是0041AE68处,以确认send函数如何修改,在ollydbg中在解密存储完后的跳转位置004016BE设置断点,打开服务端,F9运行程序,输入字段点击注册,停在断点,数据窗口中,搜索41AE68地址如下:
可以看到解密后数据存放位置位于41AE68~41AEC1这段地址。
因此程序得到解密后的数据后,程序用到它们,必然会访问这段地址,《加密与解密》作者是写了一段IDC脚本找到程序有一段mov指令从该段获取数据,即:mov dl ,byte_41AE76,这是我们客户端输入数据中添加的随机数,但是我试了这个脚本没有获取到该指令的文本数据,只有一个空文本,不知道什么原因,所以这里直接把这个地址拿来用了。
分析一下send函数前的参数是怎么产生的,加密部分和解密的类似,这里仅解析加密前的数据如何获取的:
这里首先调用了两个计算字符串长度的函数,用于计算客户端输入的name和key的长度,把他们分别存放于var_240和var_1F8这两个参数值上;
随后调用时间相关的参数,由于中间也没有数据往寄存器上存储转移应该是在此基础上再添加随机数(调用rand函数),随后再进行与(and)操作,所以此时的eax寄存器存放随机数值,最后在地址401558处,将eax的低位地址al中的值转移到寄存器ebp的参数var_254上;
后面就是将输入的name长度、key长度、随机数值、name、key进行整合加密了。
所以我们输入数据产生的随机数依然存放于ebp寄存器的var_254上,所以这里调用send函数的修改为调用一个空白指令处,将var_254上的随机数值放到41AE76处,因为程序就是从这段地址取出我们解密后的数据,这个地址就是用于存放解密后的随机数值。
程序修改方法
No.1 send函数修改:
找个空白指令,ollydbg往下拉就行,全是int3 的中断指令,这里我选是40faa8,send位置是40163c,用eax来转移数据,将存储在var_254上的随机值放到41AE76处(原40163c位置调用call函数改为 call 0040FAA8)。
No.2 decv函数修改:
401655位置函数入栈的第一个参数修改为完成解密后位置的跳转位指令
jmp short 4016be
No.3 这里修改完成后有一个connect的网络连接错误,这里通过IDA字符串窗口定位到该网络连接错误提示框的调用位置,该会话框被包含在一个跳转位置内,将它改为强行跳转绕过该会话框的调用即可,即jmp 无条件跳转指令
ollydbg修改完成后,打开新的程序,成功!