0x00 前言
该CrackMe是网络验证。故首先在本地运行Sever端程序:
0x01 发送
首先分析程序发送数据包的内容。于send()
函数处设断后,F9运行程序并输入内容:
点击Register按钮,来到断点处:
Ctrl+F9来到主函数:
向上查看,于第二处GetDlgItemText()
函数后设断:
打开IDA Pro,从第二处GetDlgItemText()
函数后面开始分析:
图中注释详尽,不再赘述。
上图取模运算的判断由优化公式而来:
上图红色方框内指令是将Len(Name)
、Len(Key)
、Rand()%256
依次写入某一处内存区域,名之为SendMes
。绿色方框与蓝色方框内指令是将Name
、Key
依次写入到SendMes
之后。
根据左边的三处箭头可以判断是for
循环,粗略写出C代码如下:
int tmp; //var_238
int KeyLength_NameLength_3; //Len(Key)+Len(Name)+3
int b;
char SendMes[]; //Len(Name)+Len(Key)+Rnd(Time)+Name+Key
for(tmp=0;tmp<KeyLength_NameLength_3;tmp++)
{
b=SendMes[tmp];
b^=0xA6;
SendMes[tmp]=(b&0xFF);
}
由上述分析可以得知发送数据内容,验证之:
0x02 接收
清除之前所设断点,于recv()
处设断,F9运行程序并输入内容后点击Register按钮,来到断点。Ctrl+F9来到主函数:
查看缓冲区内容:
既然是加密数据,那么下面一定会有解密操作:
根据上图粗略写出C代码如下:
int tmp; //var_238
char Recv[]; //Data from server
char Decrypt[]; //0x41AE68
for(tmp=0;tmp<Len(Recv);tmp++) //Len(Recv)=0x5A
Decrypt[tmp]=Recv[tmp]^0x6E;
0x41AE68
处存放解密后数据,长度为90 Bytes,跟进查看:
0X03 判断
上图红色方框中指令处理解密后数据。《加密与解密》随书文件中给出一Python脚本如下:
#coding=utf-8
##《加密与解密》第四版
##code by DarkNess0ut
import os
import sys
def Getasm(ea_from, ea_to, range1, range2):
fp = open("code.txt","w")
ea = ea_from
while ea < ea_to:
cmd = GetMnem(ea)
if cmd == "mov" or cmd == "lea":
opcode = Dword(NextNotTail(ea)-4)
if opcode < 0: #opcode < 0,处理 mov edx, [ebp-350]指令,否则处理mov edx, [ebp+350]
opcode = (~opcode + 1)
Message("-> %08X %08X\n" % (ea, opcode))
if range1 <= opcode <= range2:
delta = opcode - range1
MakeComm(ea, "// +0x%04X" % delta) # 加注释到IDA中
fp.write("%08X %s\n" % (ea, GetDisasm(ea)))
ea = NextNotTail(ea)
fp.close()
Message("OK!")
Getasm(0x401000,0x40F951,0x41AE68,0x41AEC1);
该脚本功能是将某块指令(该例中为0x401000
——0x40F951
)内访问指定内存区域(该例中为0x41AE68
——0x41AEC1
)的指令其后添加注释并拷贝到一TXT中。笔者对其稍加修改如下:
import os
import sys
def Getasm(ea_from, ea_to, range1, range2):
fp = open("E:\\code.txt","w")
ea = ea_from
while ea < ea_to:
cmd = GetMnem(ea)
if cmd == "mov" or cmd == "lea":
opcode = Dword(NextNotTail(ea)-4)
if opcode > 0x7fffffff: #opcode < 0,处理 mov edx, [ebp-350]指令,否则处理mov edx, [ebp+350]。原作者此处逻辑虽正确,但判断表达式错误
opcode = 0x100000000-opcode
Message("--> %08X %08X\n" % (ea, opcode))
if range1 <= opcode <= range2:
delta = opcode - range1
fp.write("%08X %s\n" % (ea, GetDisasm(ea)))
MakeComm(ea, "// +0x%04X" % delta) # 加注释到IDA中,注释内容为访问内存相对于起始内存偏移量
ea=NextNotTail(ea)
while ea<ea_to:
cmd=GetMnem(ea)
if cmd!="jnz":
fp.write("%08X %s\n"%(ea,GetDisasm(ea)))
else:
break
ea=NextNotTail(ea)
fp.write("--------------------------------\n")
ea = NextNotTail(ea)
fp.close()
Message("OK!")
Alt+F7执行该脚本,Shift+F2:
TXT内容如下:
负责判断相关指令如上,可根据指令修改相应内存的内容以完成验证。同样可以修改004016BE
处指令为EB 63
达到目的: